Python is fast enough. Python programmers tend to understand the Python Cost Model, Python's strengths and weaknesses, libraries that give compiled performance, and when to use a compiled language from the start.
So why do I care? Why do I get obsessed enough to coerce Claude into running these benchmarks and writing these Plotly charts? I do not know.1
But! I do know what I care about (for now) - and today (and some of the past weekend, and perhaps some of the next one), it's definitely the cost of defining (ideally immutable) record types (AKA structs) in Python.
So let's get this out of the way: this write up is about benchmarking "Python type speed" (informally: compile-time), it is NOT about benchmarking
- serialization
- instantiation
- attribute access
- validation
- memory
Right, so that's what Python programmers often care about, because they are probably working on long running programs, like apps, servers or pipelines, where the cost of defining a type is paid upfront, one time, whereas the cost of allocation, instantiation, validation, and serialization is paid repeatedly. So yeah, if that's what you care about, this post is not for you.
But I did include instance cost benchmarks if you're curious. 😻
If you already know you care about type definition speed, then jump straight to the analysis, otherwise keep reading for my motivation and context on this subject.
"how fast to --help"
I tend to work on CLIs for developers and tooling for build systems or test suites where the time from program start to end is what we're measuring. Perhaps you've noticed that running a command from a CLI may be near instant in a compiled program, but in Python, it can easily be hundreds of milliseconds: perceptible for UX, noticeable in CI/CD, and amplified by repeated calls as part of build system tooling.
Unlike in a compiled language, Python type definitions are not free (free in the sense that they were paid for during compilation ahem, Rust). They are code to be executed on every startup. And that includes imports of libraries and their type trees and dependents trees. We'll see in the benchmarks that (evil-runtime-) metaprogramming, like decorators, metaclasses, or worse, have more of an upfront runtime type generation cost than manual type definitions.
Can we get the best of everything: a Pythonic type definition style, complete static typing and match, with the speed of a hand-written C struct, and the startup time of a compiled extension? I think so. seriously, I'm not sure, need to do more work, but I have good preliminary data
Continue reading at crumpledpaper.tech...
-
If you have any ideas, please LMK so I can explain it to my family. ↩
Top comments (0)