Skip to content

gh-144764: Made dataclasses construct automatic docstrings lazily - #144765

Closed
adamchainz wants to merge 1 commit into
python:mainfrom
adamchainz:adamchainz/dataclass-lazy-docstring
Closed

gh-144764: Made dataclasses construct automatic docstrings lazily#144765
adamchainz wants to merge 1 commit into
python:mainfrom
adamchainz:adamchainz/dataclass-lazy-docstring

Conversation

@adamchainz

@adamchainzadamchainz commented Feb 12, 2026

Copy link
Copy Markdown
Contributor

Move the default docstring construction to occur on-access through a descriptor.

Verified with tprof and this script that generates 10k dataclasses:

fromdataclassesimportdataclassforiinrange(10_000):
@dataclassclassExample:
field1: intfield2: strfield3: float

Before:

$ tprof -t dataclasses._process_class example.py
🎯 tprof results:
function calls total mean ± σ min … max
dataclasses._process_class() 10000 5s 485μs ± 120μs 458μs … 6ms

After:

$ PYTHONPATH=Lib/ uvx tprof -t dataclasses._process_class example.py 🎯 tprof results:
function calls total mean ± σ min … max
dataclasses._process_class() 10000 3s 275μs ± 131μs 245μs … 6ms

The mean time spent in _process_class() has dropped from 485μs to 275μs, a ~42% time saving (admittedly skewed due to the small size of the dataclass).

@johnslavik

johnslavik commented Feb 12, 2026

Copy link
Copy Markdown
Member

DocDescriptor isn't meant to be public API. Can we rename it to a private class?

Move the default docstring construction to occur on-access through a descriptor.
Verified with [tprof](https://github.com/adamchainz/tprof) and this script that generates 10k dataclasses:
```py
from dataclasses import dataclass
for i in range(10_000):
@DataClass
class Example:
field1: int
field2: str
field3: float
```
**Before:**
```
$ tprof -t dataclasses._process_class example.py
🎯 tprof results:
function calls total mean ± σ min … max
dataclasses._process_class() 10000 5s 485μs ± 120μs 458μs … 6ms
```
After:
```
$ PYTHONPATH=Lib/ uvx tprof -t dataclasses._process_class example.py
🎯 tprof results:
function calls total mean ± σ min … max
dataclasses._process_class() 10000 3s 275μs ± 131μs 245μs … 6ms
```
The mean time spent in `_process_class()` has dropped from 485μs to 275μs, a ~42% time saving (admittedly skewed due to the small size of the dataclass).
@adamchainz
adamchainzforce-pushed the adamchainz/dataclass-lazy-docstring branch from b69f2e5 to e2293d9CompareFebruary 13, 2026 00:07
@adamchainz

Copy link
Copy Markdown
ContributorAuthor

DocDescriptor isn't meant to be public API. Can we rename it to a private class?

Good point, done!

@danielhollas

danielhollas commented Feb 13, 2026

Copy link
Copy Markdown
Contributor

Hehe, funny, I ended doing do same trick in my recent PR #144387, with the main purpose of being able to lazy import the inspect module. It's great to see it improves dataclass creation as well (I had a hunch but didn't do careful benchmarking).

@adamchainz

Copy link
Copy Markdown
ContributorAuthor

Aha. I guess your PR wins then, with the lazy import a bonus.

@github-actions

Copy link
Copy Markdown

This PR is stale because it has been open for 30 days with no activity.

@github-actionsgithub-actionsBot added the stale Stale PR or inactive for long period of time. label May 6, 2026
@hugovk

Copy link
Copy Markdown
Member

#144387 has been merged, let's close this. Thanks anyway :)

@hugovkhugovk closed this May 6, 2026
@adamchainz
adamchainz deleted the adamchainz/dataclass-lazy-docstring branch May 14, 2026 23:13
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

awaiting reviewstaleStale PR or inactive for long period of time.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@adamchainz@johnslavik@danielhollas@hugovk