Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit e90ec36

Browse files
committed
don't memoize objects that are their own copies (closes #12422)
Patch mostly by Alex Gaynor.
1 parent 31877c9 commit e90ec36

3 files changed

Lines changed: 27 additions & 7 deletions

File tree

Lib/copy.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -173,8 +173,10 @@ def deepcopy(x, memo=None, _nil=[]):
173173
"un(deep)copyable object of type %s" % cls)
174174
y = _reconstruct(x, rv, 1, memo)
175175

176-
memo[d] = y
177-
_keep_alive(x, memo) # Make sure x lives at least as long as d
176+
# If is its own copy, don't memoize.
177+
if y is not x:
178+
memo[d] = y
179+
_keep_alive(x, memo) # Make sure x lives at least as long as d
178180
return y
179181

180182
_deepcopy_dispatch = d = {}
@@ -214,9 +216,10 @@ def _deepcopy_tuple(x, memo):
214216
y = []
215217
for a in x:
216218
y.append(deepcopy(a, memo))
217-
d = id(x)
219+
# We're not going to put the tuple in the memo, but it's still important we
220+
# check for it, in case the tuple contains recursive mutable structures.
218221
try:
219-
return memo[d]
222+
return memo[id(x)]
220223
except KeyError:
221224
pass
222225
for i in range(len(x)):
@@ -225,7 +228,6 @@ def _deepcopy_tuple(x, memo):
225228
break
226229
else:
227230
y = x
228-
memo[d] = y
229231
return y
230232
d[tuple] = _deepcopy_tuple
231233

Lib/test/test_copy.py

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -321,9 +321,24 @@ def test_deepcopy_reflexive_dict(self):
321321

322322
def test_deepcopy_keepalive(self):
323323
memo = {}
324-
x = 42
324+
x = []
325+
y = copy.deepcopy(x, memo)
326+
self.assertIs(memo[id(memo)][0], x)
327+
328+
def test_deepcopy_dont_memo_immutable(self):
329+
memo = {}
330+
x = [1, 2, 3, 4]
325331
y = copy.deepcopy(x, memo)
326-
self.assertTrue(memo[id(x)] is x)
332+
self.assertEqual(y, x)
333+
# There's the entry for the new list, and the keep alive.
334+
self.assertEqual(len(memo), 2)
335+
336+
memo = {}
337+
x = [(1, 2)]
338+
y = copy.deepcopy(x, memo)
339+
self.assertEqual(y, x)
340+
# Tuples with immutable contents are immutable for deepcopy.
341+
self.assertEqual(len(memo), 2)
327342

328343
def test_deepcopy_inst_vanilla(self):
329344
class C:

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,9 @@ Core and Builtins
200200
Library
201201
-------
202202

203+
- Issue #12422: In the copy module, don't store objects that are their own copy
204+
in the memo dict.
205+
203206
- Issue #12303: Add sigwaitinfo() and sigtimedwait() to the signal module.
204207

205208
- Issue #12404: Remove C89 incompatible code from mmap module. Patch by Akira

0 commit comments

Comments
 (0)