+=
在2000年10月发布的Python 2.0中引入了类似的“增强”赋值运算符。在PEP 203中描述了其设计和原理。这些运营商宣布的目标之一是就地运营的支持。写作
a = [1, 2, 3]
a += [4, 5, 6]
应该更新列表a
到位。如果还有其他对列表的引用a
,例如当a
作为函数参数被接收时,这一点就很重要。
然而,由于许多Python类型(包括整数和字符串)都是不可变的,因此操作不一定总是在原地进行的,因此例如i += 1
对于整数,i
就不可能在原地进行操作。
总而言之,应该在可能的情况下使用扩充的赋值运算符,否则将创建一个新对象。为了实现这些设计目标,表达式的x += y
行为指定如下:
- 如果
x.__iadd__
定义,x.__iadd__(y)
则进行评估。
- 否则,评估
x.__add__
是否实施x.__add__(y)
。
- 否则,评估
y.__radd__
是否实施y.__radd__(x)
。
- 否则引发错误。
通过该过程获得的第一个结果将被分配回x
(除非结果是NotImplemented
单例,在这种情况下,查找将继续进行下一步)。
此过程允许支持就地修改的类型实现__iadd__()
。不支持就地修改的类型不需要添加任何新的魔术方法,因为Python会自动降为本质上x = x + y
。
因此,最后让我们提出您的实际问题–为什么您可以使用增强的赋值运算符将元组添加到列表中。从内存来看,其历史大致是这样的:list.__iadd__()
实现该方法只是为了调用list.extend()
Python 2.0中已经存在的方法。在Python 2.1中引入迭代器后,该list.extend()
方法已更新为可以接受任意迭代器。这些更改的最终结果是my_list += my_tuple
从Python 2.1开始起作用。list.__add__()
但是,该方法从未被视为支持任意迭代器作为右手参数–对于强类型语言,这被认为是不合适的。
我个人认为,增强运算符的实现最终在Python中过于复杂。它具有许多令人惊讶的副作用,例如以下代码:
t = ([42], [43])
t[0] += [44]
第二行引发TypeError: 'tuple' object does not support item assignment
,但无论如何都成功执行了操作 - t
将([42, 44], [43])
在执行引发错误的行之后执行。