Python对象混淆:a=b,修改b,a也改变!

13 投票
3 回答
11600 浏览
提问于 2025-04-16 09:21

我一直以为我懂Python,直到今晚。我想知道,像这样做的正确方法是什么?这是我的代码:

a = ["one", "two", "three"]
b = a  # here I want a complete copy that when b is changed, has absolutely no effect on a
b.append["four"]
print a  # a now has "four" in it

简单来说,我想知道,怎么才能正确地复制一个列表或字典,这样当我改变b的时候,a就不会跟着改变?

3 个回答

1

复制一个对象的正确方法是

 from copy import copy
 a = [1, 2, 3]
 b = copy(a)

这很简单。对于列表,有一些快捷方式:

 a = [1, 2, 3]
 b = a[:]

如果你想要连列表里面的对象也一起复制,可以使用deepcopy()。

1

这里有三种方法可以复制列表 a

第一种方法是使用切片语法:

copy_of_a = a[:]

第二种方法是使用列表构造函数:

copy_of_a = list(a)

第三种方法是使用复制模块:

from copy import copy
copy_of_a = copy(a)

这些都是浅拷贝,对于你的问题来说已经足够了。如果想了解浅拷贝和深拷贝之间的区别,可以查看复制模块的文档

18

你遇到的这个问题其实是关于“引用”的概念。在Python中,所有的对象都有一个引用。当你把一个对象同时赋值给两个名字,比如ab时,这意味着ab都指向同一个对象。

>>> a = range(3)
>>> b = a                     # same object
>>> b.append(3)
>>> a, b                      # same contents
([0, 1, 2, 3], [0, 1, 2, 3])

对于列表来说,你可以通过b = a[:]来创建一个新的列表b,这个新列表是另一个列表a的一个“拷贝”。

>>> a = range(3)
>>> b = a[:]                  # make b a new copy of a
>>> b.append(3)
>>> a, b                      # a is left unchanged
([0, 1, 2], [0, 1, 2, 3])

如果你想要一个更通用的方法来处理任何对象,可以使用copy模块。浅拷贝会复制你正在拷贝的对象中存储的引用,而深拷贝则会递归地为所有对象创建新的拷贝。

>>> a = [range(2), range(3)]
>>> b = copy.copy(a)          # shallow copy of a, equivalent to a[:]
>>> b[0] = range(4)
>>> a, b                      # setting an element of b leaves a unchanged
([[0, 1], [0, 1, 2]], [[0, 1, 2, 3], [0, 1, 2]])
>>> b[1].append(3)
>>> a, b                      # modifying an element of b modifies the element in a
([[0, 1], [0, 1, 2, 3]], [[0, 1, 2, 3], [0, 1, 2, 3]])

>>> a = [range(2), range(3)]
>>> b = copy.deepcopy(a)      # deep recursive copy of a
>>> b[1].append(3)
>>> a, b                      # modifying anything in b leaves a unchanged
([[0, 1], [0, 1, 2]], [[0, 1], [0, 1, 2, 3]])

撰写回答