表达式 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 += xi = 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的变化而发生改变,就像函数的参数不宜使用可变对象作为关键字参数一样

results matching ""

    No results matching ""