关于python:通过旧版本修改列表副本的Bug

Bug where copy of a list is being modified through the old one

我在python中处理矩阵,在花了几个小时调试程序之后,设法将问题跟踪到这个代码中,其中矩阵的所有非零项都均匀地增加了。

1
2
3
4
5
6
7
8
list2=[[1,2],[0,4]]
list1=list2
for row in list1:
    for i in range(0,len(row)):
        if row[i]!=0:
            row[i]=row[i]+10
print(list1) #returns [[11,12],[0,14]], as expected
print(list2) #returns [[11,12],[0,14]], want to return [[1,2],[0,4]]

我在这里遗漏了一些基本的东西。我认为通过声明list1=list2,创建了一个新的列表,其余的代码在保持list2不变的情况下进行了修改。

有什么问题,怎么解决?


问题是,您没有复制实际列表

通过执行list1 = list2操作,您只需将句柄复制到list1所指的列表中,为了提供实际副本,您必须明确表示这是您想要的。

示例

1
2
3
4
a = [1,2,3];
b = a
c = list(a) # create a new list, copying the elements in `a`
d = a[:]    # equivalent to `list(a)` (with a slightly weird syntax)
1
2
a[1] = 99
c[1] = 0
1
2
3
4
print (a) # [1,99,3]
print (b) # [1,99,3]
print (c) # [1,0,3]
print (d) # [1,2,3]

解决办法;一路复制

您遇到的问题将显示在其他位置,因为您在列表中有列表。为了同时进行深度复制,建议使用copy.deepcopy,如下例所示。

1
import copy
1
list1 = copy.deepcopy (list2)

文档

  • docs.python.org-8.17。拷贝-浅拷贝和深拷贝操作

进一步阅读

  • 如何在python中克隆或复制列表?
  • 复制列表的最佳方法是什么?
  • 在python中深度复制列表

此代码:

1
2
list2=[[1,2],[0,4]]
list1=list2

没有在list1中创建新的列表,它只是将名称list1绑定到与list2相同的对象。因此,通过名称list2对列表所做的任何更改也将通过list1可见。

您可以使用copy模块:

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

list1现在指的是list2的副本,对清单的更改只会通过list2反映出来。

对于包含更复杂对象(如其他列表)的列表,copy.deepcopy()将生成嵌套对象的递归副本。