通过旧列表修改列表副本的错误

Posted

技术标签:

【中文标题】通过旧列表修改列表副本的错误【英文标题】:Bug where copy of a list is being modified through the old one 【发布时间】:2016-01-08 17:22:23 【问题描述】:

我在 python 中处理矩阵,花了几个小时尝试调试程序后,设法将问题本质上追溯到这段代码,其中矩阵的所有非零条目都均匀增加。

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=deepcopy(list2) Immutable vs mutable types - Python的可能重复 【参考方案1】:

这段代码:

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

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

您可以使用copy 模块:

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

list1 现在将引用list2 的副本,对列表的更改将仅通过list2 反映。

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

【讨论】:

我刚刚尝试了这个更改,但它仍然为两者返回 [[11,12],[0,14]] list1 = list2[:] 是浅拷贝 太棒了,我永远不会接受这个。大学里有一整门关于python的课程,没有提到任何阶段。【参考方案2】:

问题;您没有复制实际列表

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

示例

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)
a[1] = 99
c[1] = 0
print (a) # [1,99,3]
print (b) # [1,99,3]
print (c) # [1,0,3]
print (d) # [1,2,3]

解决方案;一直向下复制

您遇到的问题将出现在另一个位置,因为您在 list 中有 lists。为了一次性制作一个副本,建议使用copy.deepcopy,如下例所示。

import copy
list1 = copy.deepcopy (list2)

文档

docs.python.org - 8.17. copy — Shallow and deep copy operations

进一步阅读

How to clone or copy a list in Python? What is the best way to copy a list? Deep copy a list in Python

【讨论】:

以上是关于通过旧列表修改列表副本的错误的主要内容,如果未能解决你的问题,请参考以下文章

修改嵌套列表的副本会修改原始列表[重复]

python循环修改列表注意事项

Python 列表函数

我是不是需要同步对仅由一个线程修改的列表的访问?

Python ❀ 列表与元组

Python ❀ 列表与元组