Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions Lib/copy.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,9 +122,8 @@ def deepcopy(x, memo=None):
if memo is None:
memo = {}
else:
y = memo.get(d, None)
if y is not None:
return y
if d in memo:
return memo[d]

copier = _deepcopy_dispatch.get(cls)
if copier is not None:
Expand Down
12 changes: 12 additions & 0 deletions Lib/test/test_copy.py
Original file line number Diff line number Diff line change
Expand Up @@ -939,6 +939,18 @@ def m(self):
self.assertIs(g.b.__self__, g)
g.b()

def test_deepcopy_memo_none_result(self):
# Objects whose deepcopy result is None must still be memoized.
call_count = 0
class C:
def __deepcopy__(self, memo):
nonlocal call_count
call_count += 1
return None
obj = C()
copy.deepcopy([obj, obj, obj])
self.assertEqual(call_count, 1)
Comment thread
eendebakpt marked this conversation as resolved.
Resolved


class TestReplace(unittest.TestCase):

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Fix :func:`copy.deepcopy` so that an object whose deep copy is ``None`` is
still memoized. The memo miss was detected with ``None``, which is a valid
result, so such objects were copied again on every reference. Patch by
tonghuaroot.
Comment thread
eendebakpt marked this conversation as resolved.
Resolved
Loading