有人告诉我,+=与I = I +的标准符号有不同的效果。是否存在i += 1与i = i + 1不同的情况?
这完全取决于对象i。
+=调用__iadd__方法(如果它存在——如果它不存在则返回__add__),而+调用__add__方法1或在少数情况下调用__radd__方法2。
从API的角度来看,__iadd__应该用于就地修改可变对象(返回发生突变的对象),而__add__应该返回某个对象的新实例。对于不可变对象,这两个方法都返回一个新实例,但是__iadd__将把新实例放在当前命名空间中,其名称与旧实例相同。这就是为什么
i = 1
i += 1
实际上,你得到了一个新的整数,并将它赋值在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]
注意在第一个例子中,由于b和a引用同一个对象,当我对b使用+=时,它实际上改变了b (a也看到了这个变化——毕竟,它引用了同一个列表)。然而,在第二种情况下,当我执行b = b +[1,2,3]时,这将获得b引用的列表并将其与新的列表[1,2,3]连接。然后它将连接的列表存储在当前命名空间中为b——不管b之前是什么行。
在表达式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. exe__radd__将在foo_instance之前执行。__add__如果bar_instance的类型是foo_instance类型的子类(例如issubclass(Bar, Foo))。这样做的基本原理是Bar在某种意义上是一个比Foo“更高级别”的对象,所以Bar应该获得覆盖Foo行为的选项。
在后台,i += 1做了类似这样的事情:
try:
i = i.__iadd__(1)
except AttributeError:
i = i.__add__(1)
而i = i + 1是这样的:
i = i.__add__(1)
这有点过于简化,但你可以理解:Python通过创建__iadd__方法和__add__方法,为类型提供了一种特殊处理+=的方法。
其意图是可变类型,如list,将在__iadd__中改变自身(然后返回self,除非你正在做一些非常棘手的事情),而不可变类型,如int,将不会实现它。
例如:
>>> l1 = []
>>> l2 = l1
>>> l1 += [3]
>>> l2
[3]
因为l2和l1是同一个物体,你改变了l1,你也改变了l2。
But:
>>> l1 = []
>>> l2 = l1
>>> l1 = l1 + [3]
>>> l2
[]
这里,你没有突变l1;相反,您创建了一个新列表l1 +[3],并反弹名称l1以指向它,让l2指向原始列表。
(在+=版本中,您还重新绑定了l1,只是在这种情况下,您将它重新绑定到它已经绑定的同一个列表上,所以您通常可以忽略这部分。)
下面是一个直接比较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]
推荐文章
- Python dataframe pandas使用int删除列
- 使用os.walk()在Python中递归遍历目录
- 在Python中,什么时候“i += x”与“i = i + x”不同?
- Python Flask,如何设置内容类型
- 删除字符串中的字符列表
- 当你的应用程序有一个tests目录时,在Django中运行一个特定的测试用例
- 如何合并一个透明的png图像与另一个图像使用PIL
- 使用散射数据集生成热图
- python:将脚本工作目录更改为脚本自己的目录
- 如何以编程方式获取python.exe位置?
- 如何跳过循环中的迭代?
- 使用Pandas为字符串列中的每个值添加字符串前缀
- ImportError:没有名为matplotlib.pyplot的模块
- 在python中遍历对象属性
- 如何在Python中使用方法重载?