Skip to content

Commit 4cfa695

Browse files
authored
pythonGH-141686: Break cycles created by JSONEncoder.iterencode (pythonGH-141687)
1 parent daafacf commit 4cfa695

File tree

2 files changed

+16
-16
lines changed

2 files changed

+16
-16
lines changed

Lib/json/encoder.py

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -264,17 +264,6 @@ def floatstr(o, allow_nan=self.allow_nan,
264264

265265
def _make_iterencode(markers, _default, _encoder, _indent, _floatstr,
266266
_key_separator, _item_separator, _sort_keys, _skipkeys, _one_shot,
267-
## HACK: hand-optimized bytecode; turn globals into locals
268-
ValueError=ValueError,
269-
dict=dict,
270-
float=float,
271-
id=id,
272-
int=int,
273-
isinstance=isinstance,
274-
list=list,
275-
str=str,
276-
tuple=tuple,
277-
_intstr=int.__repr__,
278267
):
279268

280269
def _iterencode_list(lst, _current_indent_level):
@@ -311,7 +300,7 @@ def _iterencode_list(lst, _current_indent_level):
311300
# Subclasses of int/float may override __repr__, but we still
312301
# want to encode them as integers/floats in JSON. One example
313302
# within the standard library is IntEnum.
314-
yield buf + _intstr(value)
303+
yield buf + int.__repr__(value)
315304
elif isinstance(value, float):
316305
# see comment above for int
317306
yield buf + _floatstr(value)
@@ -374,7 +363,7 @@ def _iterencode_dict(dct, _current_indent_level):
374363
key = 'null'
375364
elif isinstance(key, int):
376365
# see comment for int/float in _make_iterencode
377-
key = _intstr(key)
366+
key = int.__repr__(key)
378367
elif _skipkeys:
379368
continue
380369
else:
@@ -399,7 +388,7 @@ def _iterencode_dict(dct, _current_indent_level):
399388
yield 'false'
400389
elif isinstance(value, int):
401390
# see comment for int/float in _make_iterencode
402-
yield _intstr(value)
391+
yield int.__repr__(value)
403392
elif isinstance(value, float):
404393
# see comment for int/float in _make_iterencode
405394
yield _floatstr(value)
@@ -434,7 +423,7 @@ def _iterencode(o, _current_indent_level):
434423
yield 'false'
435424
elif isinstance(o, int):
436425
# see comment for int/float in _make_iterencode
437-
yield _intstr(o)
426+
yield int.__repr__(o)
438427
elif isinstance(o, float):
439428
# see comment for int/float in _make_iterencode
440429
yield _floatstr(o)
@@ -458,4 +447,13 @@ def _iterencode(o, _current_indent_level):
458447
raise
459448
if markers is not None:
460449
del markers[markerid]
461-
return _iterencode
450+
451+
def _iterencode_once(o, _current_indent_level):
452+
nonlocal _iterencode, _iterencode_dict, _iterencode_list
453+
try:
454+
yield from _iterencode(o, _current_indent_level)
455+
finally:
456+
# Break reference cycles due to mutually recursive closures:
457+
del _iterencode, _iterencode_dict, _iterencode_list
458+
459+
return _iterencode_once
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Break reference cycles created by each call to :func:`json.dump` or
2+
:meth:`json.JSONEncoder.iterencode`.

0 commit comments

Comments
 (0)