python / cpython

The Python programming language
https://www.python.org
Other
62.68k stars 30.06k forks source link

PEP 649: Avoid creation of function objects for `__annotate__` #124157

Open JelleZijlstra opened 2 weeks ago

JelleZijlstra commented 2 weeks ago

Currently, when a class, function, or module has any annotations, we always generate an __annotate__ function object at import time. A function object takes 168 bytes. But in most cases, all of the relevant fields on an __annotate__ function are predictable (there's no docstring and no defaults or kwdefaults, the name is __annotate__, etc.). So we could save significant memory by constructing only a smaller object and constructing the function on demand when somebody asks for it (by accessing __annotate__).

We need the following to create an __annotate__ function object:

I am thinking of a format where __annotate__ can be any of the following:

__annotate__ getters would have to recognize the second and third cases and translate them into function objects on the fly. As a result, users accessing .__annotate__ would never see the tuple, though those who peek directly into a module or class's __dict__ might.

Other related opportunities for optimization:

JelleZijlstra commented 2 weeks ago

We could internally create a more streamlined "mini-codeobject" and materialize the real code object only when necessary

Maybe a variation of this could be that we create a bytestring with the marshalled code object, and unmarshal it only on demand.

JelleZijlstra commented 1 week ago

Tools like functools.wraps would unnecessarily force materialization of the annotate function. Not sure there's an elegant solution for this.

The proposal in #124342 would actually fix this, because we make it so the wrapper accesses the wrapped function's .__annotate__ lazily.