小编典典

Python中的“i += x”何时与“i = i + x”不同?

all

有人告诉我,它+=的效果可能与 . 的标准符号不同i = i +。是否存在与i += 1不同的情况i = i + 1


阅读 70

收藏
2022-06-11

共1个答案

小编典典

这完全取决于对象i

+=调用该__iadd__方法(如果它存在
-__add__如果它不存在则回退)而+调用__add__方法1或__radd__在少数情况下调用方法2。

从 API 的角度来看,__iadd__应该用于 就地 修改可变对象(返回已变异的对象),而__add__应该返回某物的 新实例 。对于
不可变 对象,这两种方法都返回一个新实例,但__iadd__会将新实例放在当前命名空间中,并与旧实例具有相同的名称。这就是为什么

i = 1
i += 1

似乎增加了i。实际上,您会得到一个新整数并将其分配在“之上” i——失去对旧整数的一个引用。在这种情况下,i += 1与 完全相同i = i + 1。但是,对于大多数可变对象,情况就不同了:

作为一个具体的例子:

a = [1, 2, 3]
b = a
b += [1, 2, 3]
print a  #[1, 2, 3, 1, 2, 3]
print b  #[1, 2, 3, 1, 2, 3]

相比:

a = [1, 2, 3]
b = a
b = b + [1, 2, 3]
print a #[1, 2, 3]
print b #[1, 2, 3, 1, 2, 3]

注意在第一个示例中,由于ba引用同一个对象,当我使用+=on时b,它实际上发生了变化b(并且也a看到了这种变化——毕竟,它引用的是同一个列表)。然而,在第二种情况下,当我这样做时b = b + [1, 2, 3],这将获取b引用的列表并将其与新列表连接起来[1, 2, 3]。然后它将连接的列表存储在当前命名空间中b——不考虑b之前的行。


1在表达式x + y中,如果x.__add__没有实现或者如果x.__add__(y)返回NotImplemented x
并且y有不同的类型
,然后x + y尝试调用y.__radd__(x)。所以,如果你有

foo_instance += bar_instance

如果Foo没有实现__add__,或者__iadd__这里的结果是一样的

foo_instance = bar_instance.__radd__(bar_instance, foo_instance)

2在表达式中, 如果 类型是(例如)类型的子类foo_instance + bar_instancebar_instance.__radd__将在之前尝试。这样做的理由是,从某种意义上说,这是一个“更高级别”的对象,因此应该可以选择覆盖的行为。foo_instance.__add__
__bar_instance``foo_instance``issubclass(Bar, Foo)``Bar``Foo``Bar``Foo

2022-06-11