Uh oh!
There was an error while loading. Please reload this page.
gh-137855: Lazy import inspect module in dataclasses - #144387
Conversation
| # 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
danielhollas
commented
Feb 2, 2026
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) |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
ca36c68 to
6bc6199CompareUh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
I believe we should add a NEWS entry, because it is user-facing change (at least in the performance terms). |
DavidCEllis
commented
Feb 16, 2026
As a side effect that may be worth noting, deferring @dataclassclassExample:
examples: list[Example]
print(Example.__doc__)Before: "Example(examples: list[ForwardRef('Example', is_class=True, owner=<class '__main__.Example'>)])"PR: 'Example(examples: list[__main__.Example])'Every dataclass is getting its own Following on from this, the Deferring Footnotes
|
johnslavik
commented
Feb 16, 2026
They could; that would be nice. |
DavidCEllis
commented
Feb 16, 2026
Ideally with the new annotations, uses of |
sergey-miryanov
commented
Feb 17, 2026
I'm not sure we should mix changes for |
hugovk
commented
Apr 2, 2026
@danielhollas If you open a new PR with the lazy imports and global regex I'm happy to merge those. I'd prefer someone else to review the autodoc stuff. |
DavidCEllis
commented
Apr 2, 2026
@hugovk worth noting as it was one of the driving forces behind this that you lose a chunk of the benefit in One way of encouraging people to document their classes I guess 🙂 . |
Thanks, I could do, but note that deferring re without deferring inspect is pointless since inspect imports re as well. (and it also wouldn't help |
hugovk
commented
Apr 11, 2026
danielhollas
commented
Apr 11, 2026
I was wrong, I forgot that I made |
danielhollas
commented
Apr 11, 2026
Alright, #148379 has been merged (thanks Hugo!) so this PR is now only about lazy importing |
Uh oh!
There was an error while loading. Please reload this page.
Co-authored-by: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com>
danielhollas
commented
Apr 18, 2026
danielhollas
commented
Apr 25, 2026
Hi all, just a note that I will be away for two weeks starting 1st of May. |






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: Support zero argument super with dataclasses when slots=True #124455)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 deferred 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.