在这个问题上,我一直在撞墙。我创建一个列表并制作4个副本,其中只有一个共享相同的内存索引。如果我更改原始列表,也会以某种方式更改其中3个副本,其中2个具有不同的内存索引。只有当我使用与原始命令相同的命令创建列表时,我才能创建一个不受原始更改影响的列表。这怎么可能?这是我的控制台的输出:
>>> orig=[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 123, 0]]
>>> id(orig)
151498220
>>> copy1=orig #same index
>>> id(copy1)
151498220
>>> copy2=orig[:] #different index
>>> id(copy2)
151498348
>>> copy3=list(orig) #different index
>>> id(copy3)
151503020
>>> copy4=[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 123, 0]]
>>> id(copy4)
151498636
>>> orig[0][1]=34
>>> copy1
[[0, 34, 0, 0], [0, 0, 0, 0], [0, 0, 123, 0]] #expected, same memory index
>>> copy2
[[0, 34, 0, 0], [0, 0, 0, 0], [0, 0, 123, 0]] #WTF?!?!?
>>> copy3
[[0, 34, 0, 0], [0, 0, 0, 0], [0, 0, 123, 0]] #ARGH!!!
>>> copy4
[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 123, 0]] #workaround?
>>> id(orig)
151498220
>>> id(copy1)
151498220
>>> id(copy2)
151498348
>>> id(copy3)
151503020
>>> id(copy4)
151498636
内存索引没有改变,但是列表被改变了。只有copy1应该已更改,因为它具有与orig相同的内存索引。
答案 0 :(得分:10)
那是因为你只是在创建一个浅层副本。您需要创建一个深层副本。
根据copy模块doc:
- 浅复制构造一个新的复合对象,然后(尽可能)将对它的引用插入到找到的对象中 原文。
- 深层复制构造一个新的复合对象,然后以递归方式将副本插入到原始对象中找到的对象。
您可以通过比较内部列表的ID来验证它:
>>> orig=[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 123, 0]]
>>> id(orig)
151498220
>>> copy2=orig[:] #different index
>>> id(copy2)
151498348
>>> id(copy2[0]) == id(orig[0]) # inner list have same id
True
您可以使用copy.deepcopy(x)
创建deepcopy
:
>>> import copy
>>>
>>> copy3 = copy.deepcopy(orig)
>>>
>>> id(copy3[0]) == id(orig[0]) # inner list have different id
False
>>> orig[0][3] = 34
>>>
>>> orig
[[0, 34, 0, 0], [0, 0, 0, 0], [0, 0, 123, 0]]
>>> copy3
[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 123, 0]]
答案 1 :(得分:0)
您的列表是names的列表,而不是您正在考虑的列表列表。当您使用列出的任何方法(切片,基于旧列表创建新列表等)制作列表副本时,您将创建一个新的外部列表,但新列表中的名称引用相同的内部列表作为旧的名字。
# One through three are all examples of:
first_list, second_list, third_list = [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 123, 0]
original = [first_list, second_list, third_list]
another_list = original[:]
# We do indeed have another list
assert id(original) != id(another_list)
# But the *references* in the list are pointing at the same underlying child list
assert id(original[0]) == id(another_list[0])
答案 2 :(得分:0)
这是因为虽然外部列表(copy1
,copy2
等)是单独的对象,但它们的子列表都是对您在orig
中创建的相同列表的引用。尝试做:
id(orig[0]) == id(copy3[0]) #should return True
为了对列表对象和的所有对象进行深度复制,请使用deepcopy
。