gh-137855: Lazy import inspect module in dataclasses#144387
gh-137855: Lazy import inspect module in dataclasses#144387danielhollas wants to merge 9 commits intopython:mainfrom
inspect module in dataclasses#144387Conversation
|
|
||
| # If this is a wrapped function, unwrap it. | ||
| member = inspect.unwrap(member) | ||
| if not isinstance(member, type) and hasattr(member, '__wrapped__'): |
There was a problem hiding this comment.
This check was copied from the while loop in inspect.unwrap
|
Deferring the call to $ ./python -m cProfile -m _colorize | head 20
5604 function calls (5484 primitive calls) in 0.007 seconds
Ordered by: cumulative time
ncalls tottime percall cumtime percall filename:lineno(function)
9/1 0.004 0.000 0.007 0.007 {built-in method builtins.exec}
1 0.000 0.000 0.007 0.007 <string>:1(<module>)
1 0.000 0.000 0.007 0.007 <frozen runpy>:199(run_module)
1 0.000 0.000 0.007 0.007 <frozen runpy>:65(_run_code)
1 0.000 0.000 0.007 0.007 _colorize.py:1(<module>)
7 0.000 0.000 0.006 0.001 dataclasses.py:1432(wrap)
7 0.000 0.000 0.006 0.001 dataclasses.py:986(_process_class)
7 0.000 0.000 0.004 0.001 dataclasses.py:478(add_fns_to_class)
4 0.000 0.000 0.001 0.000 inspect.py:3343(signature)
4 0.000 0.000 0.001 0.000 inspect.py:3056(from_callable)
12/4 0.000 0.000 0.001 0.000 inspect.py:2437(_signature_from_callable)
4 0.000 0.000 0.001 0.000 inspect.py:2331(_signature_from_function)
71/11 0.000 0.000 0.000 0.000 annotationlib.py:907(get_annotations)
8 0.000 0.000 0.000 0.000 dataclasses.py:541(__annotate__)
17/9 0.000 0.000 0.000 0.000 annotationlib.py:1114(_get_and_call_annotate) |
ca36c68 to
6bc6199
Compare
Lib/dataclasses.py
Outdated
| import abc | ||
| from reprlib import recursive_repr | ||
|
|
||
| lazy import inspect |
There was a problem hiding this comment.
This is at this point perhaps the first use of lazy import in stdlib. Not sure where it should go in terms of sorting the imports?
There was a problem hiding this comment.
Not sure we follow any particular guideline. Personally I'd keep it in the same line as the original import -- the change is then more localized. Not my call though!
There was a problem hiding this comment.
Agree, I moved it, since another core dev expressed similar sentiment over at #144756
|
I believe we should add a NEWS entry, because it is user-facing change (at least in the performance terms). |
inspectmodule is slow to import (see #117865) and is dragging down dataclasses with it.There are currently only two uses of
inspectin dataclasses, but they are a bit tricky to inline since they are on a direct code path when the@dataclassdecorator is executed.inspect.signatureis used to autogenerate class docstring (if one is not provided already)inspect.unwrapis used in a rather esoteric code path only for slotted classes, added in gh-90562: Improve zero argument support forsuper()in dataclasses whenslots=True#124692)For 1. I have used a descriptor protocol to generate the
__doc__attribute on demand (this is my first time messing with descriptors, apologies if I overlooked something).For 2. can be defferred by calling the unwrap functions only when really necessary (and hopefully this path is not common)
Benchmarks
./python -Ximporttime -c "import dataclasses"Before
After
Overall seems to be a solid 20-30% improvement.
TODO (if things done here seem acceptable):
ensure_lazy_importstest fixture