Python:扩展列表的副本- 问题?

3

我正在使用Python 3.4。
我注意到了这个有趣的行为:

In [1]: a=[1,2,3,4,5,6,7,8,9]
In [2]: b=[10,11,12,13,14,15,16,17,18,19]
In [3]: type(a)
Out[3]: list

In [4]: a
Out[4]: [1, 2, 3, 4, 5, 6, 7, 8, 9]

In [5]: b
Out[5]: [10, 11, 12, 13, 14, 15, 16, 17, 18, 19]

In [6]: c=a
In [7]: c
Out[7]: [1, 2, 3, 4, 5, 6, 7, 8, 9]

In [8]: c.extend(b)

In [9]: c
Out[9]: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]

In [10]: a
Out[10]: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]

为什么在应用于cextend方法中修改了a
你是否观察到了相同的行为?
这是正常的吗?在这种情况下,我如何扩展c而不改变a


这是一个非常常见的Python问题。查找深拷贝和浅拷贝之间的区别。 - Loocid
1
在第6行的代码In [6]: c=a中,你没有复制列表,而是将c设置为引用a引用的相同列表。你可以通过执行id(a)id(c)来验证。 - Akavall
1
c=a 的意思是 c 是指向与 a 相同的列表的引用。如果您修改该列表,则无论您将其称为什么,您都将看到该修改。list(a) 会复制 a 所引用的列表。因此,如果您写 c=list(a),则 ca 将引用具有相同内容的 不同 列表(直到您修改其中一个为止)。 - Eric Appelt
好的,我之前不知道这个(在任何Python初学者教程中都没有看到过)。谢谢你指出来并对我的无用问题表示抱歉。 - Romn
@Romn 这不是一个无用或琐碎的问题。你所做的相当于在C编程语言中,将指针c分配给与a指向的同一内存地址。我讨厌很多Python开发人员对说,“哦,但是Python中不存在指针,所以这是技术上错误的。”事实上,使用指针作为类比是向新手直观地解释概念的好方法。技术上正确并不总是转化为有帮助。 - Dave Liu
1个回答

3
因为在几行之前您将 c 设置为 a ,所以在第行上分配 c 。 编辑: 由于我的答案不够深入,请查看以下内容。
您想通过复制 a 来将 c 作为新列表。但是有两种复制方式:浅表复制深度复制
您想要两个单独的列表,因此需要使用 deepcopy 。 您不能使用 list(),因为它会浅表复制您的列表,因此您的两个列表仍然“连接”。当您更改一个值时,另一个列表中的值也会更改。 当您使用
c = copy.deepcopy(a)

你将会得到两个不同的列表。

1
更具体地说,您需要通过执行c = list(a)c = a[:]来复制列表,否则您必须编辑原始列表,否则它不会在内存中创建新条目。 - Alexander McFarlane
当你有一个简单的列表时,可以使用[:]。但是list()只会创建一个浅拷贝。 - Tom-Oliver Heidel
在这种情况下使用 import copy 有点浪费努力。这篇帖子 还建议它速度较慢。 - Alexander McFarlane
如果你想要一个与原始列表没有关联的新列表,那么你必须这样做。如果你使用list()并对新列表进行更改,旧列表也会被更改,所以请自行尝试。深度复制是唯一的解决方案。 - Tom-Oliver Heidel
@alexmcf deepcopy的速度较慢(10毫秒;浅拷贝只需1毫秒),但由于时间非常短暂,你不会注意到任何差异。等等等等。抱歉,我已经厌倦了对此进行讨论。 - Tom-Oliver Heidel

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