在深度复制期间防止参考重用
Preventing reference re-use during deepcopy
考虑以下示例:
from copy import deepcopy
item = [0]
orig = [item, item]
copy = deepcopy(orig)
orig[0][0] = 1
print(f"{orig=} {copy=}")
copy[0][0] = 2
print(f"{orig=} {copy=}")
第一个 print
输出我所期望的,因为相同的引用在列表中重复。
orig=[[1], [1]] copy=[[0], [0]]
然而,第二个print
让我感到惊讶。
orig=[[1], [1]] copy=[[2], [2]]
我原以为 deepcopy
最终会在 copy
列表中包含两个独立的引用。相反,它维护复制的单个列表引用的 属性。我猜 the docs:
的这一部分提到了这一点
A deep copy constructs a new compound object and then, recursively, inserts copies into it of the objects found in the original.
我看到 deepcopy
函数有一个 memo
参数。有没有什么有趣的事情可以用这个参数来防止重复引用,这样最终的输出就会变成:
orig=[[1], [1]] copy=[[2], [0]]
哈,这似乎比我想象的要容易,但我 90% 确定这是邪恶的。如果有人发布更好的答案或解释为什么这很糟糕,我会删除它。
实施一个 dict
,仅 假装 设置一个值。然后示例 returns 相同引用的单独副本。
class NoMemo(dict):
def __setitem__(self, key, value):
return value
...
copy = deepcopy(orig, memo=NoMemo())
...
打印:
orig=[[1], [1]] copy=[[0], [0]]
orig=[[1], [1]] copy=[[2], [0]]
如果您的全部目的是复制可能来自 JSON 的数据,即 list、dict、string、numbers、bool,那么您可以简单地实现自己的函数:
def copy_jsonlike(data):
if isinstance(data, list):
return [copy_jsonlike(x) for x in data]
elif isinstance(data, dict):
return {k: copy_jsonlike(v) for k,v in data.items()}
else:
return data
它的额外好处是可能比 copy.deepcopy
更快
或者,您的原始解决方案 json.loads(json.dumps(data))
也不错。
考虑以下示例:
from copy import deepcopy
item = [0]
orig = [item, item]
copy = deepcopy(orig)
orig[0][0] = 1
print(f"{orig=} {copy=}")
copy[0][0] = 2
print(f"{orig=} {copy=}")
第一个 print
输出我所期望的,因为相同的引用在列表中重复。
orig=[[1], [1]] copy=[[0], [0]]
然而,第二个print
让我感到惊讶。
orig=[[1], [1]] copy=[[2], [2]]
我原以为 deepcopy
最终会在 copy
列表中包含两个独立的引用。相反,它维护复制的单个列表引用的 属性。我猜 the docs:
A deep copy constructs a new compound object and then, recursively, inserts copies into it of the objects found in the original.
我看到 deepcopy
函数有一个 memo
参数。有没有什么有趣的事情可以用这个参数来防止重复引用,这样最终的输出就会变成:
orig=[[1], [1]] copy=[[2], [0]]
哈,这似乎比我想象的要容易,但我 90% 确定这是邪恶的。如果有人发布更好的答案或解释为什么这很糟糕,我会删除它。
实施一个 dict
,仅 假装 设置一个值。然后示例 returns 相同引用的单独副本。
class NoMemo(dict):
def __setitem__(self, key, value):
return value
...
copy = deepcopy(orig, memo=NoMemo())
...
打印:
orig=[[1], [1]] copy=[[0], [0]]
orig=[[1], [1]] copy=[[2], [0]]
如果您的全部目的是复制可能来自 JSON 的数据,即 list、dict、string、numbers、bool,那么您可以简单地实现自己的函数:
def copy_jsonlike(data):
if isinstance(data, list):
return [copy_jsonlike(x) for x in data]
elif isinstance(data, dict):
return {k: copy_jsonlike(v) for k,v in data.items()}
else:
return data
它的额外好处是可能比 copy.deepcopy
或者,您的原始解决方案 json.loads(json.dumps(data))
也不错。