3

如果我有这个 Python 代码:

foo = [3, 5, 9]
bar = foo
bar.append(9)
print(foo)

它返回

[3, 5, 9, 9]

这肯定意味着当我附加9到时bar,它也受到影响foo。如何使变量bar等于foo,但这样当我编辑时bar,它不起作用foo

4

4 回答 4

5

您正在更改一个可变值,因此您需要进行显式复制:

bar = list(foo)

或者

bar = foo[:]

在 Python 中分配名称时,您所做的只是存储对该值的引用。在不创建列表副本的情况下,两者都foo引用bar了同一个列表。

对于非可变值,这不是问题;您替换对字符串的引用以指向不同的值。

但是列表(大多数类的和dictset和实例)是可变的。你没有改变foo,你改变了引用的foo。你做到了foo.append(9),Python 将其视为:

  • 找到foo所指的值。
  • 找到该.append值的属性。这将返回一个列表实例的方法。
  • 调用方法,传入值9。这会改变列表。

Python 名称本身只不过是标签,指向实际值。您可以将值视为气球,将名称视为小纸标签,而分配是将标签绑定到气球的行为。bar = foo创建了第二个纸标签,它被绑在完全相同的气球上。

请参阅我的这个较旧的答案,其中我将气球比喻推向更多。

于 2013-05-03T15:35:50.433 回答
2

你制作一个副本:

bar = foo[:]  #copy of foo
bar.append(9)

这与 python 如何处理赋值有关。赋值说“把右边的对象存储在本地命名空间中左边的名字下”。因此,在您的情况下,您有 foo 和 bar 引用同一个对象,这就是为什么附加到一个对象也会影响另一个对象。

当使用通常对对象进行操作的操作符(例如+=)时,使用不可变对象会使事情变得更有趣。例如,请参阅我的答案和更多解释。

于 2013-05-03T15:35:22.510 回答
2

在创建原始副本的同时删除对其的所有引用(因此您无法编辑原始副本)时,您使用深层复制。

http://docs.python.org/2/library/copy.html

import copy
bar = copy.deepcopy(foo)
于 2013-05-03T15:43:33.090 回答
2

使用deepcopy

>>> from copy import deepcopy
>>> foo = [3, 5, 9]
>>> bar = deepcopy(foo)
>>> bar.append(9)
>>> print(foo)
[3, 5, 9]
>>> print bar
[3, 5, 9, 9]
于 2013-05-03T15:43:50.967 回答