Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
19 changes: 2 additions & 17 deletions Lib/copy.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ def deepcopy(x, memo=None):
d = id(x)
if memo is None:
memo = {}
memo[id(memo)] = []
else:
y = memo.get(d, None)
if y is not None:
Expand Down Expand Up @@ -159,7 +160,7 @@ def deepcopy(x, memo=None):
# If is its own copy, don't memoize.
if y is not x:
memo[d] = y
_keep_alive(x, memo) # Make sure x lives at least as long as d
memo[id(memo)].append(x) # Make sure x lives at least as long as d
return y

_atomic_types = frozenset({types.NoneType, types.EllipsisType, types.NotImplementedType,
Expand Down Expand Up @@ -209,22 +210,6 @@ def _deepcopy_method(x, memo): # Copy instance methods

del d

def _keep_alive(x, memo):
"""Keeps a reference to the object x in the memo.

Because we remember objects by their id, we have
to assure that possibly temporary objects are kept
alive by referencing them.
We store a reference at the id of the memo, which should
normally not be used unless someone tries to deepcopy
the memo itself...
"""
try:
memo[id(memo)].append(x)
except KeyError:
# aha, this is the first one :-)
memo[id(memo)]=[x]

def _reconstruct(x, memo, func, args,
state=None, listiter=None, dictiter=None,
*, deepcopy=deepcopy):
Expand Down
3 changes: 3 additions & 0 deletions Lib/test/test_copy.py
Original file line number Diff line number Diff line change
Expand Up @@ -435,19 +435,22 @@ def test_deepcopy_reflexive_dict(self):

def test_deepcopy_keepalive(self):
memo = {}
memo[id(memo)] = []
x = []
y = copy.deepcopy(x, memo)
self.assertIs(memo[id(memo)][0], x)

def test_deepcopy_dont_memo_immutable(self):
memo = {}
memo[id(memo)] = []
x = [1, 2, 3, 4]
y = copy.deepcopy(x, memo)
self.assertEqual(y, x)
# There's the entry for the new list, and the keep alive.
self.assertEqual(len(memo), 2)

memo = {}
memo[id(memo)] = []
x = [(1, 2)]
y = copy.deepcopy(x, memo)
self.assertEqual(y, x)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Improve performance :meth:`copy.deepcopy` setting keep alive key on the memo construction.
Loading