12 ms·
HPy – A better C API for Python
- murkt 2y agoImagine how different the Python ecosystem could be, if this was done 20 years ago.
- lifthrasiir 2y agoUnless it was done at the very beginning, I doubt it would have been even possible because the current C API is the remnant from that very first public version.
- foolfoolz 2y agopython has one of the most fractured development ecosystems of any moderately used language. i’m pretty convinced python is a language that attracts poor development practices and magnifies them due to its flexibility. the people who love it don’t understand the extreme flexibility makes it fragile at scale and are willing to put up with its annoyances in an almost stockholm syndrome way
- bvrmn 2y agoThe reason is a popularity not a technical one. It's inevitable to get a diverse interest to improve different parts of ecosystem by different parties.
- Const-me 2y ago> a language that attracts poor development practices I agree, but note there’s another way to frame it: “python can be used by people who aren’t professional software developers”.
- miohtama 2y agoC/C++ is more fractured. While Python is fractured, it is nowhere near problems of C ecosystems.
- rbanffy 2y agoAs anyone who has tried to build multi-platform software with C or C++ can easily tell you. It's almost a relief AIX, Solaris, and HP/UX are either very niche, or going the way of the Dodo.
- _fizz_buzz_ 2y agoIt’s also fractured because it has such a massive user base that use it for very different applications with very different priorities.
- Quothling 2y agoI think any programming language with a lot of popularity attracts poor development practices. Simply because a lot of programmers don't actually know the underlying processes of what they build. The flip-side of this is that freedom and flexibility also gives you a lot of control. Yes, it's very easy to write bad Python. In fact it's probably one of Python's weaknesses as you point out. If you're going to iterate over a bunch of elements, you probably expect your language standard libraries to do it in an efficient way, and Python doesn't necessarily do that. What you gain by this flexibility (and arguably sometimes poor design) is that it's also possible to write really good Python and tailor it exactly to your needs. I think Python scales rather well in fact. Django is a good example, as it's a massive workhorse for a lot of the web (Instagram still uses their own version of it as one example). It does so sort of anonymously similar to how PHP and Ruby do it outside of the hype circle, but it does it. One of the advantages Python has, even when it's bad, is that it's often "good enough". 95% of the software which gets written is never really going to need to be extremely efficient. I would argue that in 2024 Go is actually the perfect combination of the good stuff from both Python and C. But those things aren't necessarily easy to get into if you're not familiar with something like memory management, (maybe strict typing?), explicit error handling and the differences between an interpreted and compiled language. Anyway I don't think Python is anymore annoying than any other language. The freedom it gives you needs to be reigned in and if you don't then you'll end up with a mess. A mess which is probably perfectly fine.
- gjvc 2y agopsst "reined in" https://www.merriam-webster.com/grammar/do-you-rein-in-or-reign-in-something https://www.merriam-webster.com/grammar/do-you-rein-in-or-re...
- Quothling 2y agoThanks! I'm not a native English speaker so I'll probably fuck this up again but it's nice to know. Reign would be cooler though. I guess I could say "you gotta reign your developers use of Python".
- trkannr 2y ago
- est 2y ago> most fractured development ecosystems of any moderately used language Can you elaborate? What's done wrong with Python and right with other "moderately used language" ? For start, C/C++ doesn't even have an official ecosystem. For Java or Golang, it looks better only because the "ecosystem" does not always include native extensions like cgo or JNI. Once you add them the complexity were no better than Python's
- rwmj 2y agoPython .pth files are horrific. Here's an actual .pth file I was dealing with the other day (from Google Cloud Storage) which completely prevents you from overriding the module using PYTHONPATH: import sys, types, os;has_mfs = sys.version_info > (3, 5);p = os.path.join(sys._getframe(1).f_locals['sitedir'], *('google',));importlib = has_mfs and __import__('importlib.util');has_mfs and __import__('importlib.machinery');m = has_mfs and sys.modules.setdefault('google', importlib.util.module_from_spec(importlib.machinery.PathFinder.find_spec('google', [os.path.dirname(p)])));m = m or sys.modules.setdefault('google', types.ModuleType('google'));mp = (m or []) and m.__dict__.setdefault('__path__',[]);(p not in mp) and mp.append(p)
- talideon 2y agoIf .pth files are the worst thing you can find to complain about, Python's doing pretty well. That horrific .pth file in question is better placed as the feet of its creators than the mechanism itself.
- rwmj 2y agoThe fact they considered allowing executable code in path lookups shows a certain attitude.
- oefrha 2y agoIt shows that the language is highly dynamic and you can patch anything? The .pth mechanism allows the party controlling the Python installation (site) to run some init code before any user code, basically an rc mechanism. Nothing more, nothing radical. Maybe you’re unhappy with the dynamism, in which case your complaint is misplaced.
- WhereIsTheTruth 2y agoit's not 'fractured', it's just fragmented, and it's not necessarily a bad thing, it gives plenty of room for R&D and experimentation if something doesn't end up working well, you pivot
- jaimebuelta 2y agoThere are only two kinds of languages: the ones people complain about and the ones nobody uses.
- poincaredisk 2y ago>the people who love it don’t understand the extreme flexibility makes it fragile at scale and are willing to put up with its annoyances in an almost stockholm syndrome way The people who love it understand that its extreme flexibility makes it applicable everywhere, while academic purity mostly doesn't work in the real work. They also prioritize getting things done over petty squabbling, but they know how to leverage available tooling where reliability is crucial. (See, I can generalize too)
- redman25 2y agoPython with types enforced by CI isn’t too bad. Or did you have something else in mind?
- analog31 2y agoWould some other language have become just as fragmented if it had gained the same level of popularity across such a broad range of user interests?
- slashdave 2y agoPerl says "hi"
- helpfulContrib 2y ago[dead]
- amelius 2y agoIt would have taken time to do this and consequently Python would have missed the race and some other language would now be #1.
- murkt 2y agoPython missed the race pretty heavily with 2to3 transition and still came out on top.
- amelius 2y agoSurvivorship bias. With version 2 they were already at the top.
- pkkm 2y ago> Python would have missed the race Why do you think that? There's no need for a Python 2->3 like transition here, it could have been done while supporting the old C API for a while.
- rich_sasha 2y agoLooks very cool. How many new extensions are written in C these days? I was under the impression it's mostly things like Boost Python, pybind or PyO3.
- aragilar 2y agoThere's also Cython. I would guess also that HPy would replace the includes of `Python.h` that pybind11 et al make in order to bind to CPython, and so existing extensions should be easier to port?
- masklinn 2y agoPyO3 is bindings to the C API, so if you're using PyO3 you're still using the C API even if you're not actually writing C.
- rich_sasha 2y agoYeah, sure, I mean, how many people write C to write an end-user Python module. There's stuff that genuinely wraps C libraries or predates higher level language wrappers, like numpy or matplotlib, but how many new modules are actually themselves written in C?
- masklinn 2y agoThe point is that’s not relevant, the issue is the API / ABI of the modules, its requirements, and its limitations, not the langage in which the modules are written.
- m_rcin 2y agofor C++ 11+, pybind11 > Boost.Python for C++ 17+, nanobind > pybind11 (both created by the same developer) ">" meaning generally better, as described at https://nanobind.readthedocs.io/en/latest/why.html https://nanobind.readthedocs.io/en/latest/why.html
- physicsguy 2y agoQuite a lot, for things like simulation code Less so for general programming.
- koe123 2y agoIs my understanding correct that this would provide version agnostic python bindings? Currently, I am building a version of my bindings separately for each version (e.g. building and linking with python 3.7, 3.8, etc.). While automated, it still makes CI/CD take quite a long time.
- gjvc 2y agoWhile automated, it still makes CI/CD take quite a long time See about using ccache -- https://ccache.dev/ https://ccache.dev/
- IshKebab 2y agoI wouldn't recommend ccache (or sccache) in CI unless you really need it. They are not 100% reliable, and any time you save from caching will be more than lost debugging the weird failures you get when they go wrong.
- gjvc 2y agoplease provide evidence for this assertion.
- IshKebab 2y agoWhy are you so skeptical? Think about how it works and then you'll understand that cache invalidation bugs are completely inevitable. Hell, cache invalidation is notoriously difficult to get right even when you aren't building it on top of a complex tool that was never designed for aggressive caching. Just search the bugs for "hash": https://github.com/ccache/ccache/issues?q=is%3Aissue+hash+is%3Aclosed+label%3Abug https://github.com/ccache/ccache/issues?q=is%3Aissue+hash+is...
- imtringued 2y agoYou can't cache based on the file contents alone. You will also need to cache based on all OS/compiler queries/variables/settings that the preprocessor depends on, since the header files might generate completely different content based on what ifdef gets triggered.
- Stem0037 2y agoIt would be interesting to see benchmarks comparing HPy extensions to equivalent Cython/pybind11 implementations in terms of performance and development time.
- normanthreep 2y agotangentially related question: is there something as simple as luajit's ffi for python? as in: give it a c header, load the shared library, it simply makes structs usable and functions callable.
- actinium226 2y agoI'm a little unclear as to how this fits in with libraries like PyBind11 or nanobind? It seems like those libraries would need to be rewritten (or new libraries with the same goals created) in order to use this in the same way?
- gghoop 2y agoI'm interested in calling go from python, gopy generates python bindings to cgo. Maybe HPy<->cgo would have less overhead.
- crabbone 2y agoIt's a no-go at this point, if you want this on MS Windows. CGo on MS Windows uses MinGW, while CPython uses MSVC. It's very hard to make this work due to name mangling. I.e. you can do this for Python from MSYS2, for example, but not for the one your users will likely have.
- masklinn 2y agoUse IPC. Go wilfully set itself apart from and against the C ABI, it’s generally not worth fighting against that.
- xiaodai 2y agoIs this thing “official”?
- trkannr 2y agoAfter cpyext and cffi, this is the third attempt, largely driven by PyPy people, to get a C-API that people want to use. If they succeed and keep the CPython "leaders" who ruined the development experience and social structure of CPython out of PyPy, PyPy might get interesting. If they don't keep them out, those "leaders" will merrily sink yet another project.
- filmor 2y agocffi replaces ctypes, which is a completely different thing. cpyext is a reimplementation of the Python C-API, so no attempt at improving the API. HPy on CPython uses the existing C-API under the hood, so there is zero need to build up some keep someone out...
- kagerl 2y agocffi is used to wrap c libraries. Only a masochist would use ctypes to wrap a whole library. While both are technically FFIs, it does not make sense to compare them. From a conceptual perspective, cffi was written to replace the C-API for C modules.
- deleted 2y ago[deleted]
- VagabundoP 2y agoExpand here on your use of double quotes and the subtext of your comment if you please.
- pkkm 2y agoVery happy to see that these issues are getting attention now. I think that the Python language being so centered on one implementation is a long-term threat to its success. Web servers, command-line programs, and embedded devices have different requirements: high post-warmup throughput, fast startup, low memory usage. They aren't necessarily best served by the same implementation. If this project succeeds in replacing Python's C API with something that doesn't expose implementation details, such as whether the implementation uses reference counting, that could make it easier both to maintain alternative implementations, and to experiment with new techniques in CPython.
- ashvardanian 2y agoHey! First of all, cool to see some activity on this front! I’ve written a fair share of pure CPython bindings and regularly post about implementing them with minimal overhead (<https://ashvardanian.com/posts/discount-on-keyword-arguments-in-python/ https://ashvardanian.com/posts/discount-on-keyword-arguments...>) and would love to share a few recommendations, questions, and concerns :) Just a suggestion to help you grow—I'd restructure the landing page (<https://hpyproject.org/ https://hpyproject.org/>) and the README of the repo (<https://github.com/hpyproject/hpy https://github.com/hpyproject/hpy>). It could benefit from some examples to clarify the "Nicer API" bullet point. Maybe these could be taken from the API documentation page (<https://docs.hpyproject.org/en/latest/api.html https://docs.hpyproject.org/en/latest/api.html>). The page could also be more convincing with some supporting stats in favor of PyPy, GraalPython, and other Python runtimes. A reader like me might not be sure if they have enough usage and are stable enough. Avoiding singletons and having encapsulated context objects like `HPyContext` is definitely a great thing to have, especially in the multi-threaded Python future or in complex environments with multiple sub-interpreters. But this doesn't really solve the problem if, under the hood, the `HPyContext` still redirects to CPython's singleton. I've also looked at the linked benchmarks (<https://pypy.org/posts/2019/12/hpy-kick-off-sprint-report-1840829336092490938.html https://pypy.org/posts/2019/12/hpy-kick-off-sprint-report-18...>). They are dated from 2019, five years ago, and already mention CPython's `METH_FASTCALL` fast calling convention, but it seems like they are not compared to it. In either case, parsing arguments from one "ll" string specifier is hardly a detailed benchmark if the underlying magic isn't explained. I occasionally do one-off benchmarks as well, but it's better to describe the principle—why the thing is supposed to be faster. For example, if you're concerned about performance, you'd just parse the arguments directly from the tuple without string formatters—like this: <https://github.com/ashvardanian/SimSIMD/blob/80cc4bcaddbdee9a0c0e991e13376c234aff3b3f/python/lib.c#L929-L1066> It’s more error-prone, but it would be cool to see if a high-level solution can achieve under a 10% latency penalty. Hope this is useful :)
- fforflo 2y agoSomething I don't see being mentioned in the comments: What's a really frustrating part of working with the C API? Setting up the compile/link flags! The python3-config works generally well but is only available at the OS level. But you don't want to mess with that (e.g., to access pip-installed packages). Beyond that, everything is a mess! python3 -m venv doesn't even bother creating such a script. anaconda/miniconda? Don't even try!. So every package pollutes their build scripts with many hardcoded `python3 -c "import sys: print..."` calls. I've opened a CPython/PR that may help a bit by adding `python3 -m sysconfig --json` flag [0] [0] https://github.com/python/cpython/pull/123318 https://github.com/python/cpython/pull/123318