好,让我用一个简单的例子来解释这个问题:
l = [[0]]*3 # makes the array [[0], [0], [0]]
l[0][0] = 42 # l becomes [[42], [42], [42]]
from copy import deepcopy
m = deepcopy(l) # m becomes [[42], [42], [42]]
m[0][0] = 2 # m becomes [[2], [2], [2]]
这是一个基本的共享参考问题。除非通常发生这种问题,否则deepcopy
是我们的朋友。
目前,我提出这个解决我deepcopy
出卖问题:
l = [[0]]*3 # makes the array [[0], [0], [0]]
import JSON
m = JSON.loads(JSON.dumps(l)) # m becomes [[0], [0], [0]] with no self references
我正在寻找一种效率低下,愚蠢的方式来处理自我共享引用。
当然,我不会故意创建这样的数组,但是我需要处理有人给我的代码一个数组的情况。在大型阵列上运行我的“解决方案”是缓慢的,而且我有嵌套数组的多层次,我不能做一个字符串,这个大的活物。
答案 0 :(得分:10)
这是一种适用于列表,字典和不可变值的任意组合的方法。
def very_deep_copy(obj):
if isinstance(obj, list):
return [very_deep_copy(item) for item in obj]
elif isinstance(obj, dict):
return {k: very_deep_copy(v) for k,v in obj.items()}
else:
return obj
l = [[0]]*3
m = very_deep_copy(l)
m[0][0] = 2
print(m)
结果:
[[2], [0], [0]]
答案 1 :(得分:7)
我将挑战这样一个假设,即正确的做法是复制共享对象。你这么说
当然,我不会故意创建这样的数组,但是我需要处理有人给我的代码一个数组的情况。
但是,如果有人向您传递包含意外对象共享的输入,则他们的代码存在错误。如果您的代码注意到该错误,则您的代码应通过抛出异常来告知他们,以帮助他们修复其错误。
大多数代码只是假设输入没有任何不需要的对象共享。如果您仍然想检测到它,则手动遍历可能是最好的选择,尤其是因为您的输入应该是JSON可序列化的:
def detect_duplicate_references(data):
_detect_duplicate_references(data, set())
def _detect_duplicate_references(data, memo):
if isinstance(data, (dict, list)):
if id(data) in memo:
raise ValueError(f'multiple references to object {data} detected in input')
memo.add(id(data))
if isinstance(data, list):
for obj in data:
_detect_duplicate_references(obj, memo)
if isinstance(data, dict):
for obj in data.values():
_detect_duplicate_references(obj, memo)
答案 2 :(得分:2)
l = [[0] for _ in range(3)]
l[0][0] = 2
print(l)
打印:
[[2], [0], [0]]
此外,顺便说一句,在代码中 deepcopy()
给出了它的输出,因为您传入了一个列表,该列表已经具有共享相同引用的元素。
from copy import deepcopy
m = deepcopy(l)
m[0][0] = 3
print(l) # prints [[2], [0], [0]]
print(m) # prints [[3], [0], [0]]
您可以在这里看到它确实达到了我们的预期
答案 3 :(得分:1)
假定将仅列出结构类型,这应适用于任意深度和复杂性的列表:
def customcopy(l):
return [customcopy(e) if type(e) is list else e for e in l]
l = [[0]]*3
x = customcopy(l)
x[0][0] = 3
>>> x
[[3], [0], [0]]
答案 4 :(得分:0)
不确定它是否有效,但是您可以尝试:
l = [deepcopy(elt) for elt in l]
答案 5 :(得分:0)
对于单层深层副本,您只需检查引用即可。对于更深的副本,只需递归执行即可。
from copy import deepcopy
def copy_value(l):
l = list(l)
new_list = []
while l:
item = l.pop(0)
if item not in new_list:
new_list.append(item)
else:
new_list.append(deepcopy(item))
return new_list
l = [[0]]*3
m = copy_value(l)
m[0][0] = 2
print(m)
打印
[[2], [0], [0]]
答案 6 :(得分:0)
列表理解的另一种方法:
def super_deep_copy(l):
return [i.copy() for i in l]
l = [[0]]*3
l = super_deep_copy(l)
l[0][0] = 2
现在:
print(l)
是:
[[2], [0], [0]]