https://github.com/python/cpython/commit/4cfa695c953e5dfdab99ade81cee960ddf4b106d
commit: 4cfa695c953e5dfdab99ade81cee960ddf4b106d
branch: main
author: Brandt Bucher <[email protected]>
committer: brandtbucher <[email protected]>
date: 2025-11-18T09:51:18-08:00
summary:

GH-141686: Break cycles created by JSONEncoder.iterencode (GH-141687)

files:
A Misc/NEWS.d/next/Library/2025-11-17-16-53-49.gh-issue-141686.V-xaoI.rst
M Lib/json/encoder.py

diff --git a/Lib/json/encoder.py b/Lib/json/encoder.py
index 5cf6d64f3eade6..4c70e8b75ed132 100644
--- a/Lib/json/encoder.py
+++ b/Lib/json/encoder.py
@@ -264,17 +264,6 @@ def floatstr(o, allow_nan=self.allow_nan,
 
 def _make_iterencode(markers, _default, _encoder, _indent, _floatstr,
         _key_separator, _item_separator, _sort_keys, _skipkeys, _one_shot,
-        ## HACK: hand-optimized bytecode; turn globals into locals
-        ValueError=ValueError,
-        dict=dict,
-        float=float,
-        id=id,
-        int=int,
-        isinstance=isinstance,
-        list=list,
-        str=str,
-        tuple=tuple,
-        _intstr=int.__repr__,
     ):
 
     def _iterencode_list(lst, _current_indent_level):
@@ -311,7 +300,7 @@ def _iterencode_list(lst, _current_indent_level):
                     # Subclasses of int/float may override __repr__, but we 
still
                     # want to encode them as integers/floats in JSON. One 
example
                     # within the standard library is IntEnum.
-                    yield buf + _intstr(value)
+                    yield buf + int.__repr__(value)
                 elif isinstance(value, float):
                     # see comment above for int
                     yield buf + _floatstr(value)
@@ -374,7 +363,7 @@ def _iterencode_dict(dct, _current_indent_level):
                 key = 'null'
             elif isinstance(key, int):
                 # see comment for int/float in _make_iterencode
-                key = _intstr(key)
+                key = int.__repr__(key)
             elif _skipkeys:
                 continue
             else:
@@ -399,7 +388,7 @@ def _iterencode_dict(dct, _current_indent_level):
                     yield 'false'
                 elif isinstance(value, int):
                     # see comment for int/float in _make_iterencode
-                    yield _intstr(value)
+                    yield int.__repr__(value)
                 elif isinstance(value, float):
                     # see comment for int/float in _make_iterencode
                     yield _floatstr(value)
@@ -434,7 +423,7 @@ def _iterencode(o, _current_indent_level):
             yield 'false'
         elif isinstance(o, int):
             # see comment for int/float in _make_iterencode
-            yield _intstr(o)
+            yield int.__repr__(o)
         elif isinstance(o, float):
             # see comment for int/float in _make_iterencode
             yield _floatstr(o)
@@ -458,4 +447,13 @@ def _iterencode(o, _current_indent_level):
                 raise
             if markers is not None:
                 del markers[markerid]
-    return _iterencode
+
+    def _iterencode_once(o, _current_indent_level):
+        nonlocal _iterencode, _iterencode_dict, _iterencode_list
+        try:
+            yield from _iterencode(o, _current_indent_level)
+        finally:
+            # Break reference cycles due to mutually recursive closures:
+            del _iterencode, _iterencode_dict, _iterencode_list
+
+    return _iterencode_once
diff --git 
a/Misc/NEWS.d/next/Library/2025-11-17-16-53-49.gh-issue-141686.V-xaoI.rst 
b/Misc/NEWS.d/next/Library/2025-11-17-16-53-49.gh-issue-141686.V-xaoI.rst
new file mode 100644
index 00000000000000..87e9cb8d69bfbc
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2025-11-17-16-53-49.gh-issue-141686.V-xaoI.rst
@@ -0,0 +1,2 @@
+Break reference cycles created by each call to :func:`json.dump` or
+:meth:`json.JSONEncoder.iterencode`.

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]

Reply via email to