Why This Python Performance Trick Doesn’t Matter Anymore
-
This post did not contain any content.
Why This Old Python Performance Trick Doesn’t Matter Anymore
A deep dive into Python’s name resolution, bytecode, and how CPython 3.11 quietly made a popular optimization irrelevant.
(blog.codingconfessions.com)
-
This post did not contain any content.
Why This Old Python Performance Trick Doesn’t Matter Anymore
A deep dive into Python’s name resolution, bytecode, and how CPython 3.11 quietly made a popular optimization irrelevant.
(blog.codingconfessions.com)
TLDR: 3.11 is twice as fast as 3.10 at doing global name lookups, so an old speedup hack of aliasing a global function locally isn't needed.
For example, when calling len() in a loop, going l=len, and calling l() in the loop was faster in 3.10. In 3.11, moreso in 3.13, it's almost a wash.
However, the author says this:
Accessing functions through a module [e.g. math.sin()] or a deep attribute chain can still carry overhead. Creating a local alias or using "from module import name" continues to be effective in those situations.
But when I look at the numbers, I would say 3.13 is pretty close to making it an unnecessary optimization in general. A little subjective on how you interpret the numbers.
Great info, but this was like trying to use a recipe and reading the author's life story to get there.
-
TLDR: 3.11 is twice as fast as 3.10 at doing global name lookups, so an old speedup hack of aliasing a global function locally isn't needed.
For example, when calling len() in a loop, going l=len, and calling l() in the loop was faster in 3.10. In 3.11, moreso in 3.13, it's almost a wash.
However, the author says this:
Accessing functions through a module [e.g. math.sin()] or a deep attribute chain can still carry overhead. Creating a local alias or using "from module import name" continues to be effective in those situations.
But when I look at the numbers, I would say 3.13 is pretty close to making it an unnecessary optimization in general. A little subjective on how you interpret the numbers.
Great info, but this was like trying to use a recipe and reading the author's life story to get there.
Thanks for the summary!
Yeah, in Python each . is a dictionary lookup. The cost of having a dynamic language where the compiler can do pretty much no optimizations (and yes, Python does have a compiler).
In static languages these lookups can be collapsed to a single pointer address by the compiler.
-
TLDR: 3.11 is twice as fast as 3.10 at doing global name lookups, so an old speedup hack of aliasing a global function locally isn't needed.
For example, when calling len() in a loop, going l=len, and calling l() in the loop was faster in 3.10. In 3.11, moreso in 3.13, it's almost a wash.
However, the author says this:
Accessing functions through a module [e.g. math.sin()] or a deep attribute chain can still carry overhead. Creating a local alias or using "from module import name" continues to be effective in those situations.
But when I look at the numbers, I would say 3.13 is pretty close to making it an unnecessary optimization in general. A little subjective on how you interpret the numbers.
Great info, but this was like trying to use a recipe and reading the author's life story to get there.
I'm surprised about the module lookup thing, since I assumed it was just syntax sugar to do
from ... import ...
. We do thefrom
syntax almost everywhere, but I've been replacing huge import blocks with a module import (e.g. constants) just to clean up the imports a bit and git conflicts.Looks like I'll need to keep this in mind until we upgrade to 3.13.