Python append()方法与深、浅拷贝

 |
总阅读量


  最近在用Python实现粒子群算法时,我要用列表记录粒子群算法迭代时种群的情况,但是却发生了一些问题。调试浪费了一些时间,故在此记录下来。

背景

这段Python代码:

>>> list1 = []
>>> list2 = [1,2,3]
>>> list1.append(list2) # 将list2追加到list1尾部
>>> print(list1)
[[1, 2, 3]]
>>> list2[1] = 0        # 改变list2第二个值
>>> print(list1)
[[1, 0, 3]]

  问题是:我将list2加入到list1后面,再去改变list2第2个元素值,结果list1中对应索引位置元素也发生改变。想想粒子群算法迭代30次寻到最优值后,但种群却一直没变,诡异至极。

深入剖析

继续看这段代码:

>>> id(list2) == id(list1[0])
True

  这表明list2在内存中的起始位置与list1[0]在内存中的位置是一样的。实际上列表list1的append()方法是将list2进行浅拷贝,把list2引用直接赋值给list1[0], list2直接作为一个对象追加到list1[0]上。这样改变list2也会改变list1[0],这就很危险了。

解决方案

  导入copy模块,对list2进行深拷贝再追加到list1尾部即可:

>>> import copy
>>> list1 = []
>>> list2 = [1,2,3]
>>> list1.append(copy.deepcopy(list2))
>>> list1
[[1, 2, 3]]
>>> list2[0] = 0
>>> list1
[[1, 2, 3]]
>>> list2
[0, 2, 3]

  深拷贝即是为list2创建一个副本再追加到list1尾部,这样list2与list1[0]就不再是同一个引用了。