5

我注意到分配(看似)奇怪的行为,这导致我多次犯编程错误。

先看下面的例子:

>>> i = 0
>>> t = (i,)
>>> t
(0,)
>>> i += 1
>>> t
(0,)

正如预期的那样,唯一元素的值t不会改变,即使在值i增加之后也是如此。

现在看到以下内容:

>>> l = [0]
>>> t = (l,)
>>> t
([0],)
>>> l[0] += 1
>>> t
([1],)  # <- ?

我不明白为什么最初的零t现在是一;如果我通过引用t...来增加它

>>> t[0][0] += 1

...我知道它的值已经改变,但在前面的例子中不是这种情况,只有l在递增时被显式引用。

我有两个问题:

  1. 为什么会这样?
  2. 有没有我应该注意的特殊规则?
4

2 回答 2

8

这是因为整数是不可变的,而列表是可变的。

>>> i = 0
>>> t = (i,)
>>> t[0] is i  # both of them point to the same immutable object
True
>>> i += 1  # We can't modify an immutable object, changing `i` simply 
            # makes it point to a new object 2.
            # All other references to the original object(0) are still intact.
>>> i
1
>>> t       # t still points to the same 0
(0,)
>>> x = y = 1
>>> id(x),id(y)
(137793280, 137793280)
>>> x += 1
>>> id(x),id(y)       #y still points to the same object
(137793296, 137793280)

对于列表:

>>> l = [0]
>>> t = (l,)       
>>> t[0] is l #both t[0] and l point to the same object [0]
True
>>> l[0] += 1 # modify [0] in-place
>>> t
([1],)
>>> l
[1]
#another exmple
>>> x = y =[]    # x, y point to the same object
>>> x.append(1)  # list.append modifies the list in-place
>>> x, y          
([1], [1]) 
>>> x = x + [2]  # only changes x, x now points to a new object
>>> x, y
([1, 2], [1])
于 2013-06-10T12:31:02.290 回答
2

在第二个示例中,t(元组)持有对l(列表)的引用。当您这样做时l[0] += 1,您正在更改列表,但元组仍然包含对列表的引用。在第一个例子中,当你这样做时i += 1,你实际上是在创建一个新的整数,你的元组不包含对它的引用。请参阅我不久前写的这个答案,以更深入地解释+=运算符及其实际实现方式。

于 2013-06-10T12:35:17.420 回答