更改一个列表中的值会更改另一个列表中具有不同内存ID的值

时间:2013-07-17 18:43:33

标签: python python-2.7

在这个问题上,我一直在撞墙。我创建一个列表并制作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相同的内存索引。

3 个答案:

答案 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)

这是因为虽然外部列表(copy1copy2等)是单独的对象,但它们的子列表都是对您在orig中创建的相同列表的引用。尝试做:

id(orig[0]) == id(copy3[0]) #should return True

为了对列表对象的所有对象进行深度复制,请使用deepcopy