列表索引与复制

时间:2018-08-28 00:15:43

标签: python list

我有一个名为mylist

的列表

有什么区别

newlist = mylist

newlist = mylist[:]

似乎后者更安全,因为它不会基于对mylist的任何操作而使newlist发生突变

`

2 个答案:

答案 0 :(得分:2)

第一个只为列表创建另一个名称。它仍然是相同的列表。

这意味着突变newlist也会突变mylist

>>> mylist = [1, 2, 3]
>>> newlist = mylist
>>> newlist.append(4)
>>> mylist
[1, 2, 3, 4]

第二个示例实际上创建了一个列表的副本,一个实际的新列表。

>>> mylist = [1, 2, 3]
>>> newlist = mylist[:]
>>> newlist.append(4)
>>> newlist
[1, 2, 3, 4]
>>> mylist
[1, 2, 3]

您几乎没有理由为同一个对象使用两个名称,因为这可能会造成混淆并导致突变错误。

变异错误是指代码的某些部分需要某个对象(例如函数func1),而代码的某些其他部分则需要先进行突变,例如函数func2。如果func1期望对象处于初始状态,那么追踪突变发生的位置可能非常繁琐。

示例:

obj = [list of data]
same_obj = obj

func2(same_obj) # mutates the object

# hundreds of lines of code

func1(obj) # needs the initial state of the object

在上面的示例中,最好将func2的副本传递给obj。由于第一行和最后一行之间发生了很多事情,因此追踪突变错误可能非常繁琐。

答案 1 :(得分:0)

区别在于:第一个在本地命名空间中创建(或重新绑定)引用同一mylist实例的另一个名称。您可以将其视为别名。第二个创建mylist的浅表副本。

此行:

newlist = mylist

是可怕的Python。因为这不是变量名所暗示的“新列表” ,所以只是为同一列表添加了另一个名称。

这是可以接受的:

mylist_again = mylist

是否最好使用mylist[:]切片,这完全取决于上下文。有时您想要一个副本,有时您想要另一个对现有数据的引用。

  

后者似乎更安全,因为它不会基于对newlist的任何操作而使mylist变异

那不是完全正确的,因为切片只是一个浅表副本。新列表可能仍处于共享状态:

>>> mylist = [0, [1]]
>>> newlist = mylist[:]
>>> newlist[0] = 123
>>> newlist[1][0] = 456
>>> mylist
[0, [456]]
>>> newlist
[123, [456]]

同样,浅表副本是否足够取决于数据。如果您使用嵌套数据而浅表副本不够用,或者应该复制可变元素,则可以使用copy.deepcopy