Mar*_*Rob 210 python operators
我被告知+=可以有不同于标准符号的效果i = i +.有没有在这情况下i += 1会从不同i = i + 1?
mgi*_*son 314
这完全取决于对象i.
+=调用__iadd__方法(如果它存在 - __add__如果它不存在则重新开启),而在少数情况下+调用__add__方法1或__radd__方法2.
从API的角度看,__iadd__应该被用于修改可变对象到位(返回其突变的对象),而__add__应返回一个新实例的东西.对于不可变对象,两个方法都返回一个新实例,但__iadd__会将新实例放在当前命名空间中,其名称与旧实例的名称相同.这就是为什么
i = 1
i += 1
Run Code Online (Sandbox Code Playgroud)
似乎在增加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]
Run Code Online (Sandbox Code Playgroud)
相比:
a = [1, 2, 3]
b = a
b = b + [1, 2, 3]
print a #[1, 2, 3]
print b #[1, 2, 3, 1, 2, 3]
Run Code Online (Sandbox Code Playgroud)
请注意,在第一个例子,因为b和a引用同一个对象,当我使用+=上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_instance,如果类型是(例如)类型的子类,bar_instance.__radd__将在之前尝试.合理的,这是因为在某种意义上是一种"更高级"的对象不是那么应该得到压倒一切的选项的行为.foo_instance.__add__ bar_instancefoo_instanceissubclass(Bar, Foo)BarFooBarFoo
aba*_*ert 67
在幕后,i += 1做这样的事情:
try:
i = i.__iadd__(1)
except AttributeError:
i = i.__add__(1)
Run Code Online (Sandbox Code Playgroud)
虽然i = i + 1做了这样的事情:
i = i.__add__(1)
Run Code Online (Sandbox Code Playgroud)
这有点过于简单了,但你明白了:Python给类型提供了一种+=特殊处理方式,通过创建__iadd__方法和方法__add__.
意图是可变类型,比如list,会自我变异__iadd__(然后返回self,除非你做的事情非常棘手),而不可变类型,比如,将int不会实现它.
例如:
>>> l1 = []
>>> l2 = l1
>>> l1 += [3]
>>> l2
[3]
Run Code Online (Sandbox Code Playgroud)
因为l2是同一个对象l1,并且你发生了变异l1,你也会发生变异l2.
但:
>>> l1 = []
>>> l2 = l1
>>> l1 = l1 + [3]
>>> l2
[]
Run Code Online (Sandbox Code Playgroud)
在这里,你没有变异l1; 相反,您创建了一个新列表,l1 + [3]并将名称反弹l1以指向它,并l2指向原始列表.
(在+=版本中,你也是重新绑定l1,只是在那种情况下你将它重新绑定到list已经绑定的那个,所以你通常可以忽略那个部分.)
以下示例直接i += x与以下内容进行比较i = i + x:
def foo(x):
x = x + [42]
def bar(x):
x += [42]
c = [27]
foo(c); # c is not changed
bar(c); # c is changed to [27, 42]
Run Code Online (Sandbox Code Playgroud)