Python复制一个列表的列表
问题的原因是代码中使用的赋值操作(b = a)只是将b指向了a所指向的对象,而并没有创建一个新的列表对象。这意味着当修改b时,a也会发生相同的修改。这不是一个正确的解决方法,因为我们希望创建一个新的列表对象以便独立地进行修改。
解决方法是使用列表的拷贝方法来创建一个新的列表对象。以下是两种常见的拷贝方法:
1. 使用切片操作符([:])进行拷贝:
b = a[:]
示例:
>>> a = [1, 2, 3] >>> b = a[:] >>> b.append(4) >>> b [1, 2, 3, 4] >>> a [1, 2, 3]
2. 使用列表的copy()方法进行拷贝:
b = a.copy()
示例:
>>> a = [1, 2, 3] >>> b = a.copy() >>> b.append(4) >>> b [1, 2, 3, 4] >>> a [1, 2, 3]
使用这些方法,我们可以创建一个新的列表对象并进行独立的修改,而不会影响原始列表对象。
问题的出现原因是在Python中复制一个列表的列表时,使用浅拷贝方法会导致复制的列表仍然包含对原始对象的引用。这会导致对复制的列表进行修改时,原始列表也会被修改。
解决方法是使用列表解析或使用copy
模块中的方法进行深拷贝。列表解析的方法是通过创建新的列表,并使用切片操作将原始列表中的每个子列表复制到新列表中。这样可以确保新列表中的子列表是独立的,对其进行修改不会影响原始列表。
另一种方法是使用copy.deepcopy()
方法进行深拷贝。这个方法会递归地复制所有的对象,包括子列表中的对象,从而创建一个完全独立的副本。
以下是使用列表解析和copy.deepcopy()
方法进行复制的示例代码:
使用列表解析的方法:
new_list = [x[:] for x in old_list]
使用copy.deepcopy()
方法的方法:
import copy new_list = copy.deepcopy(old_list)
通过使用上述方法,可以确保复制的列表是完全独立的,对其进行任何修改都不会影响原始列表。
Python中的copy
模块提供了浅拷贝和深拷贝的功能。浅拷贝适用于复合对象(包含其他对象的对象,如列表或类实例)。它构建一个新的复合对象,并在可能的情况下将原始对象中的引用插入其中。而深拷贝则递归地构建一个新的复合对象,并在其中插入原始对象的副本。
当使用copy.copy()
进行拷贝时,默认进行的是浅拷贝。这意味着对于列表的列表的情况,你将获得一个新的外部列表副本,但它的元素仍然是原始内部列表。相反,你应该使用copy.deepcopy()
,它将创建外部和内部列表的新副本。
之所以在使用copy([1,2])
的示例中没有注意到这一点,是因为像int
这样的基本类型是不可变的,无法在不创建新实例的情况下更改它们的值。如果列表的内容是可变对象(如列表或具有可变成员的任何用户定义对象),那么对这些对象的任何修改都将在列表的两个副本中都可见。
关于拷贝还有一个问题,可以通过简单的方法获得类的拷贝吗?比如树类,可以使用简单的方法获得树对象t1的副本吗?
是的,你可以在任何定义了__copy__
和__deepcopy__
方法的对象上使用copy
模块。具体细节可以参考原始回答中的链接文档。不过,遗憾的是,Python中没有像C++等语言中那样的“预定义”拷贝操作(对于任何非平凡类,C++的自动生成的拷贝构造函数通常是错误的)。
你可以在pythontutor.com上检查在使用copy
方法时发生了什么。你可以在那里看到所有指针的可视化。