diff --git a/Lib/dataclasses.py b/Lib/dataclasses.py index 482a4c61039184..7d046d02de35ba 100644 --- a/Lib/dataclasses.py +++ b/Lib/dataclasses.py @@ -1,6 +1,4 @@ -import re import sys -import copy import types import inspect import keyword @@ -8,6 +6,8 @@ import annotationlib import abc from reprlib import recursive_repr +lazy import copy +lazy import re __all__ = ['dataclass', @@ -217,9 +217,8 @@ def __repr__(self): _POST_INIT_NAME = '__post_init__' # String regex that string annotations for ClassVar or InitVar must match. -# Allows "identifier.identifier[" or "identifier[". -# https://bugs.python.org/issue33453 for details. -_MODULE_IDENTIFIER_RE = re.compile(r'^(?:\s*(\w+)\s*\.)?\s*(\w+)') +# This regular expression is compiled on demand so that 're' module can be imported lazily +_MODULE_IDENTIFIER_RE = None # Atomic immutable types which don't require any recursive handling and for which deepcopy # returns the same object. We can provide a fast-path for these types in asdict and astuple. @@ -804,10 +803,17 @@ def _is_type(annotation, cls, a_module, a_type, is_type_predicate): # a eval() penalty for every single field of every dataclass # that's defined. It was judged not worth it. - match = _MODULE_IDENTIFIER_RE.match(annotation) + # String regex that string annotations for ClassVar or InitVar must match. + # Allows "identifier.identifier[" or "identifier[". + # https://github.com/python/cpython/issues/77634 for details. + global _MODULE_IDENTIFIER_RE + if _MODULE_IDENTIFIER_RE is None: + _MODULE_IDENTIFIER_RE = re.compile(r'(?:\s*(\w+)\s*\.)?\s*(\w+)') + + match = _MODULE_IDENTIFIER_RE.prefixmatch(annotation) if match: ns = None - module_name = match.group(1) + module_name = match[1] if not module_name: # No module name, assume the class's module did # "from dataclasses import InitVar". @@ -817,7 +823,7 @@ def _is_type(annotation, cls, a_module, a_type, is_type_predicate): module = sys.modules.get(cls.__module__) if module and module.__dict__.get(module_name) is a_module: ns = sys.modules.get(a_type.__module__).__dict__ - if ns and is_type_predicate(ns.get(match.group(2)), a_module): + if ns and is_type_predicate(ns.get(match[2]), a_module): return True return False diff --git a/Misc/NEWS.d/next/Library/2026-04-11-12-32-38.gh-issue-137855.tsVny_.rst b/Misc/NEWS.d/next/Library/2026-04-11-12-32-38.gh-issue-137855.tsVny_.rst new file mode 100644 index 00000000000000..0ec08c2d2fd54a --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-04-11-12-32-38.gh-issue-137855.tsVny_.rst @@ -0,0 +1,2 @@ +Improve import time of :mod:`dataclasses` module by lazy importing :mod:`re` +and :mod:`copy` modules.