Skip to content

Commit a827615

Browse files
committed
Improve import time of dataclasses
1 parent 1bccd6c commit a827615

File tree

2 files changed

+17
-7
lines changed

2 files changed

+17
-7
lines changed

Lib/dataclasses.py

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,7 @@
1-
import re
21
import sys
3-
import copy
42
import types
5-
import inspect
63
import keyword
74
import itertools
8-
import annotationlib
95
import abc
106
from reprlib import recursive_repr
117

@@ -219,7 +215,7 @@ def __repr__(self):
219215
# String regex that string annotations for ClassVar or InitVar must match.
220216
# Allows "identifier.identifier[" or "identifier[".
221217
# https://bugs.python.org/issue33453 for details.
222-
_MODULE_IDENTIFIER_RE = re.compile(r'^(?:\s*(\w+)\s*\.)?\s*(\w+)')
218+
_MODULE_IDENTIFIER_RE = None
223219

224220
# Atomic immutable types which don't require any recursive handling and for which deepcopy
225221
# returns the same object. We can provide a fast-path for these types in asdict and astuple.
@@ -747,6 +743,11 @@ def _is_type(annotation, cls, a_module, a_type, is_type_predicate):
747743
# correct global and local namespaces. However that would involve
748744
# a eval() penalty for every single field of every dataclass
749745
# that's defined. It was judged not worth it.
746+
global _MODULE_IDENTIFIER_RE
747+
748+
if _MODULE_IDENTIFIER_RE is None:
749+
import re
750+
_MODULE_IDENTIFIER_RE = re.compile(r'^(?:\s*(\w+)\s*\.)?\s*(\w+)')
750751

751752
match = _MODULE_IDENTIFIER_RE.match(annotation)
752753
if match:
@@ -982,6 +983,7 @@ def _process_class(cls, init, repr, eq, order, unsafe_hash, frozen,
982983
# actual default value. Pseudo-fields ClassVars and InitVars are
983984
# included, despite the fact that they're not real fields. That's
984985
# dealt with later.
986+
import annotationlib
985987
cls_annotations = annotationlib.get_annotations(
986988
cls, format=annotationlib.Format.FORWARDREF)
987989

@@ -1160,6 +1162,8 @@ def _process_class(cls, init, repr, eq, order, unsafe_hash, frozen,
11601162

11611163
if not getattr(cls, '__doc__'):
11621164
# Create a class doc-string.
1165+
import inspect
1166+
11631167
try:
11641168
# In some cases fetching a signature is not possible.
11651169
# But, we surely should not fail in this case.
@@ -1318,6 +1322,8 @@ def _add_slots(cls, is_frozen, weakref_slot, defined_fields):
13181322
# original class. We can break out of this loop as soon as we
13191323
# make an update, since all closures for a class will share a
13201324
# given cell.
1325+
import inspect
1326+
13211327
for member in newcls.__dict__.values():
13221328
# If this is a wrapped function, unwrap it.
13231329
member = inspect.unwrap(member)
@@ -1484,7 +1490,8 @@ def _asdict_inner(obj, dict_factory):
14841490
# generator
14851491
return obj_type(_asdict_inner(v, dict_factory) for v in obj)
14861492
else:
1487-
return copy.deepcopy(obj)
1493+
from copy import deepcopy
1494+
return deepcopy(obj)
14881495

14891496

14901497
def astuple(obj, *, tuple_factory=tuple):
@@ -1544,7 +1551,8 @@ def _astuple_inner(obj, tuple_factory):
15441551
return obj_type((_astuple_inner(k, tuple_factory), _astuple_inner(v, tuple_factory))
15451552
for k, v in obj.items())
15461553
else:
1547-
return copy.deepcopy(obj)
1554+
from copy import deepcopy
1555+
return deepcopy(obj)
15481556

15491557

15501558
def make_dataclass(cls_name, fields, *, bases=(), namespace=None, init=True,
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Improve import time of :mod:`dataclasses` by lazy importing :mod:`re`,
2+
:mod:`copy`, :mod:`inspect` and :mod:`annotationlib`. Patch by Semyon Moroz.

0 commit comments

Comments
 (0)