Python复制一个列表的列表

18
我正在使用Python 3.4.1。
对于单个列表a=[1,2],如果我复制它,b = a.copy(),当我更改b中的项目时,它不会更改a中的项目。
然而,当我定义一个列表的列表(实际上是矩阵)a = [[1,2],[3,4]],当我分配b = a.copy()时,我对列表b做的任何事情实际上都会影响a
我检查了它们的地址,它们是不同的。
有人能告诉我为什么吗?
注:我所做的是b [0] [0] = x,并且a中的项也发生了更改。
3个回答

27

来自copy模块的文档:

浅复制和深复制仅适用于复合对象 (包含其他对象的对象,如列表或类实例):

  • 浅复制构造一个新的复合对象,然后(在可能的范围内)向其中插入对原始对象中找到的对象的引用。
  • 深复制构造一个新的复合对象,然后以递归方式将原始对象中找到的对象的副本插入其中。

当您调用常规的copy.copy()时,您正在执行一个浅复制。这意味着在列表嵌套列表的情况下,您将获得外部列表的新副本,但它将包含原始内部列表作为其元素。相反,您应该使用copy.deepcopy(),它将创建外部和内部列表的新副本。

您没有注意到这一点的原因是,对于像int这样的基本数据类型是不可变的,因此不可能改变它们的值而不创建新的实例。如果列表的内容代替了可变对象(如列表或任何具有可变成员的用户定义对象),则这些对象的任何修改都将在列表的两个副本中看到。


谢谢!还有一个关于复制的问题。我能复制一个类吗?比如树类,我能用简单的方法复制一些树对象t1吗? - jack
是的,您可以在任何定义了__copy____deepcopy__方法的对象上使用copy模块。有关详细信息,请参阅原始答案中链接的文档。不幸的是,在Python中没有像C++这样的“预定义”复制操作(通常这是一件好事,因为C++的自动生成的复制构造函数对于任何非平凡类都经常是错误的)。 - aruisdante
@jack,当你使用copy方法在pythontutor.com上查看,您可以看到所有指针的可视化效果。 - Arpad Horvath -- Слава Україні

10
也许可以使用列表推导式来实现,例如:
new_list = [x[:] for x in old_list]

...虽然如果您的矩阵超过一层,使用列表推导可能比使用deepcopy更不优美。

编辑-浅拷贝仍将包含对列表内部对象的引用。例如...

>>> this = [1, 2]
>>> that = [33, 44]
>>> stuff = [this, that]
>>> other = stuff[:]
>>> other
[[1, 2], [33, 44]]
>>> other[0][0] = False
>>> stuff
[[False, 2], [33, 44]]    #the same problem as before
>>> this
[False, 2]                #original list also changed
>>> other = [x[:] for x in stuff]
>>> other
[[False, 2], [33, 44]]
>>> other[0][0] = True
>>> other
[[True, 2], [33, 44]]
>>> stuff
[[False, 2], [33, 44]]    #copied matrix is different
>>> this
[False, 2]                #original was unchanged by this assignment

1
对于普通读者来说,使用copy方法比使用其他方法要更加清晰明了,而且性能稍微更好一些。 - aruisdante
当然,这是有的。但列表推导式是最具Python风格的,所以我想这取决于什么被认为是“清晰”的,以及对谁来说。无论如何,如果矩阵嵌套太深,那么我的建议就不会很有帮助,但对于单个维度,我认为它还不错。 - user890167

-21

非常简单,只需这样做:

b = a

示例:

>>> a = [1, 2, 3]
>>> b = a
>>> b.append(4)
>>> b
[1, 2, 3, 4]
>>> a
[1, 2, 3, 4]

3
这只是让ab指向同一个对象,这不是正确的解决方案。 - Adam_G

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接