表达式 i+=x 区别 i=i+x
1. 演示
In [1]: la = range(3)
In [2]: lb = la
In [3]: la
Out[3]: [0, 1, 2]
In [4]: lb
Out[4]: [0, 1, 2]
In [5]: lb += [3]
In [6]: la
Out[6]: [0, 1, 2, 3]
In [7]: lb
Out[7]: [0, 1, 2, 3]
In [8]: lc = range(3)
In [9]: ld = lc
In [10]: ld = ld + [3]
In [11]: lc
Out[11]: [0, 1, 2]
In [12]: ld
Out[12]: [0, 1, 2, 3]
In [13]: id(la)
Out[13]: 4492528168
In [14]: id(lb)
Out[14]: 4492528168
In [15]: id(lc)
Out[15]: 4492593416
In [16]: id(ld)
Out[16]: 4490185976
从上面可以看出 la与ld是一样的,lc与ld是不一样的,说明 i += x
与 i = i + x
在某些情况下是不等价的。
2. 区别
+=
操作首先会尝试调用对象的 __iadd__
方法,如果没有该方法,那么尝试调用__add__
方法
2.1. __add__和 __iadd__ 的区别
__add__
方法接收两个参数,返回它们的和,两个参数的值均不会改变。__iadd__
方法同样接收两个参数,但它是属于 in-place 操作,就是说它会改变第一个参数的值,因为这需要对象是可变的,所以对于不可变对象没有iadd方法
>>> hasattr(int, '__iadd__')
False
>>> hasattr(list, '__iadd__')
True
显然,整数对象是没有__iadd__
的,而列表对象提供了__iadd__
方法。
>>> lb += [3] # += 操作调用的是__iadd__方法,他会原地修改lb指向的那个对象本身的值
>>> ld = ld + [3] # 的 + 操作调用的是 __add__ 方法,该方法会返回一个新的对象,原来的对象保持不变,lc还是指向原来的对象,而ld已经指向一个新的对象。
以上就是表达式 i += x 与 i = i + x 的区别。因此对于列表进行 += 操作时,会存在潜在的bug,因为la会因为lb的变化而发生改变,就像函数的参数不宜使用可变对象作为关键字参数一样