为什么列表在Python中以持久的方式链接?

Why are lists linked in Python in a persistent way?

设置了一个变量。另一个变量设置为第一个。第一个更改值。第二个没有。这是自时代开始编程的本质。

1
2
3
4
5
6
7
>>> a = 1
>>> b = a
>>> b = b - 1
>>> b
0
>>> a
1

然后我将其扩展到python列表。声明并附加一个列表。另一个列表声明为等于第一个列表。第二个列表中的值更改。奇怪的是,第一个列表中的值虽然没有直接作用,但也会发生变化。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
>>> alist = list()
>>> blist = list()
>>> alist.append(1)
>>> alist.append(2)
>>> alist
[1, 2]
>>> blist
[]
>>> blist = alist
>>> alist.remove(1)
>>> alist
[2]
>>> blist
[2]
>>>

为什么会这样?

我该如何防止这种情况发生——我希望alist不受blist变化的影响(如果你愿意的话,是不变的)?


python变量实际上不是变量,而是对对象的引用(类似于c中的指针)。在http://foobarnbaz.com/2012/07/08/understanding-python-variables中有一个很好的解释,对初学者来说。/

让自己相信这一点的一种方法是尝试:

1
2
3
4
5
6
a=[1,2,3]
b=a
id(a)
68617320
id(b)
68617320

id返回给定对象的内存地址。因为这两个列表都是相同的,这意味着改变一个列表会影响另一个列表,因为它们实际上是相同的。


python中的变量绑定的工作方式是:将对象赋给变量。

1
2
a = 4
b = a

两者都指向4

1
b = 9

现在,b指向其他地方。

列表也会发生同样的情况:

1
2
3
a = []
b = a
b = [9]

现在,b有了新的价值,而a有了旧的价值。

到目前为止,一切都很清楚,对于可变和不变的对象,您有相同的行为。

现在出现了你的误解:这是关于修改物体。

lists是可变的,因此如果您改变一个列表,那么可以通过存在的所有变量("名称绑定")看到修改:

1
2
3
4
5
6
7
8
9
10
a = []
b = a  # the same list
c = [] # another empty one

a.append(3)
print a, b, c # a as well as b = [3], c = [] as it is a different one

d = a[:] # copy it completely
b.append(9)
# now a = b = [3, 9], c = [], d = [3], a copy of the old a resp. b


发生的情况是,当您执行以下操作时,会创建对同一列表的另一个引用:

1
blist = alist

因此,blist引用了与alist相同的列表。因此,对单个列表的任何修改都将影响alistblist

如果要复制整个列表,而不仅仅是创建引用,可以执行以下操作:

1
blist = alist[:]

实际上,您可以使用id()自己检查参考:

1
2
3
4
5
6
7
8
9
10
11
12
>>> alist = [1,2]
>>> blist = []
>>> id(alist)
411260888
>>> id(blist)
413871960
>>> blist = alist
>>> id(blist)
411260888
>>> blist = alist[:]
>>> id(blist)
407838672

这是来自python文档的相关引用:

Assignment statements in Python do not copy objects, they create bindings between a target and an object. For collections that are mutable or contain mutable items, a copy is sometimes needed so one can change one copy without changing the other.


基于此帖:

Python passes references-to-objects by value (like Java), and
everything in Python is an object. This sounds simple, but then you
will notice that some data types seem to exhibit pass-by-value
characteristics, while others seem to act like pass-by-reference...
what's the deal?

It is important to understand mutable and immutable objects. Some
objects, like strings, tuples, and numbers, are immutable. Altering
them inside a function/method will create a new instance and the
original instance outside the function/method is not changed. Other
objects, like lists and dictionaries are mutable, which means you can
change the object in-place. Therefore, altering an object inside a
function/method will also change the original object outside.

所以在您的示例中,您要使变量blistalist指向同一对象。因此,当从blistalist中删除元素时,它会反映在它们都指向的对象中。


简短的回答2你的问题"这是为什么?":因为在python中,整数是不可变的,而列表是可变的。

您在python文档中寻找官方参考。看看这一部分:http://docs.python.org/2/reference/simple诳stmts.html诳赋值语句

引自后者:

Assignment statements are used to (re)bind names to values and to
modify attributes or items of mutable objects

我真的很喜欢这句话,以前从没见过。它精确地回答了你的问题。

最近关于这个主题的一篇好文章是http://nedbatchelder.com/text/names.html,其中一条评论中已经提到过。