[Python-checkins] gh-103000: Optimise dataclasses asdict/astuple for common types (#103005)
AlexWaygood
webhook-mailer at python.org
Mon Apr 10 17:51:07 EDT 2023
https://github.com/python/cpython/commit/d034590294d4618880375a6db513c30bce3e126b
commit: d034590294d4618880375a6db513c30bce3e126b
branch: main
author: David Ellis <ducksual at gmail.com>
committer: AlexWaygood <Alex.Waygood at Gmail.com>
date: 2023-04-10T22:50:58+01:00
summary:
gh-103000: Optimise dataclasses asdict/astuple for common types (#103005)
Co-authored-by: Carl Meyer <carl at oddbird.net>
Co-authored-by: Alex Waygood <Alex.Waygood at Gmail.com>
files:
A Misc/NEWS.d/next/Library/2023-03-24-20-49-48.gh-issue-103000.6eVNZI.rst
M Lib/dataclasses.py
diff --git a/Lib/dataclasses.py b/Lib/dataclasses.py
index 7558287bad44..4026c8b77975 100644
--- a/Lib/dataclasses.py
+++ b/Lib/dataclasses.py
@@ -222,6 +222,29 @@ def __repr__(self):
# https://bugs.python.org/issue33453 for details.
_MODULE_IDENTIFIER_RE = re.compile(r'^(?:\s*(\w+)\s*\.)?\s*(\w+)')
+# 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.
+_ATOMIC_TYPES = frozenset({
+ # Common JSON Serializable types
+ types.NoneType,
+ bool,
+ int,
+ float,
+ str,
+ # Other common types
+ complex,
+ bytes,
+ # Other types that are also unaffected by deepcopy
+ types.EllipsisType,
+ types.NotImplementedType,
+ types.CodeType,
+ types.BuiltinFunctionType,
+ types.FunctionType,
+ type,
+ range,
+ property,
+})
+
# This function's logic is copied from "recursive_repr" function in
# reprlib module to avoid dependency.
def _recursive_repr(user_function):
@@ -1291,7 +1314,9 @@ class C:
def _asdict_inner(obj, dict_factory):
- if _is_dataclass_instance(obj):
+ if type(obj) in _ATOMIC_TYPES:
+ return obj
+ elif _is_dataclass_instance(obj):
result = []
for f in fields(obj):
value = _asdict_inner(getattr(obj, f.name), dict_factory)
@@ -1363,7 +1388,9 @@ class C:
def _astuple_inner(obj, tuple_factory):
- if _is_dataclass_instance(obj):
+ if type(obj) in _ATOMIC_TYPES:
+ return obj
+ elif _is_dataclass_instance(obj):
result = []
for f in fields(obj):
value = _astuple_inner(getattr(obj, f.name), tuple_factory)
diff --git a/Misc/NEWS.d/next/Library/2023-03-24-20-49-48.gh-issue-103000.6eVNZI.rst b/Misc/NEWS.d/next/Library/2023-03-24-20-49-48.gh-issue-103000.6eVNZI.rst
new file mode 100644
index 000000000000..15f16d9eb4c1
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2023-03-24-20-49-48.gh-issue-103000.6eVNZI.rst
@@ -0,0 +1,2 @@
+Improve performance of :func:`dataclasses.astuple` and
+:func:`dataclasses.asdict` in cases where the contents are common Python types.
More information about the Python-checkins
mailing list