这里发生了一些事情。
+= 并不总是+ 然后是=。
+= 和 + 如果需要可以有不同的实现。
看看这个例子。
In [13]: class Foo:
...: def __init__(self, x=0):
...: self.x = x
...: def __add__(self, other):
...: print('+ operator used')
...: return Foo(self.x + other.x)
...: def __iadd__(self, other):
...: print('+= operator used')
...: self.x += other.x
...: return self
...: def __repr__(self):
...: return f'Foo(x={self.x})'
...:
In [14]: f1 = Foo(10)
In [15]: f2 = Foo(20)
In [16]: f3 = f1 + f2
+ operator used
In [17]: f3
Out[17]: Foo(x=30)
In [18]: f1
Out[18]: Foo(x=10)
In [19]: f2
Out[19]: Foo(x=20)
In [20]: f1 += f2
+= operator used
In [21]: f1
Out[21]: Foo(x=30)
同样,列表类对+ 和+= 有单独的实现。
使用+=实际上是在后台执行extend操作。
In [24]: l = [1, 2, 3, 4]
In [25]: l
Out[25]: [1, 2, 3, 4]
In [26]: id(l)
Out[26]: 140009508733504
In [27]: l += [5, 6, 7]
In [28]: l
Out[28]: [1, 2, 3, 4, 5, 6, 7]
In [29]: id(l)
Out[29]: 140009508733504
使用+ 创建一个新列表。
In [31]: l
Out[31]: [1, 2, 3]
In [32]: id(l)
Out[32]: 140009508718080
In [33]: l = l + [4, 5, 6]
In [34]: l
Out[34]: [1, 2, 3, 4, 5, 6]
In [35]: id(l)
Out[35]: 140009506500096
我们现在来回答你的问题。
In [36]: t = ([1, 2], [3, 4])
In [37]: t[0] += [10, 20]
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-37-5d9a81f4e947> in <module>
----> 1 t[0] += [10, 20]
TypeError: 'tuple' object does not support item assignment
In [38]: t
Out[38]: ([1, 2, 10, 20], [3, 4])
+ 运算符在这里首先执行,这意味着列表被更新(扩展)。这是允许的,因为对列表的引用(存储在元组中的值)不会改变,所以这很好。
= 然后尝试更新 tuple 内的引用,这是不允许的,因为元组是不可变的。
但实际列表被+ 改变了。
Python 未能更新对元组内列表的引用,但由于它会更新为相同的引用,因此我们作为用户看不到更改。
因此,+ 被执行,= 无法执行。 + 对tuple 中已经引用的list 进行变异,因此我们在列表中看到了变异。