Ada*_*ted 110 python loops numpy operators
我今天发现了一件奇怪的事情,并想知道是否有人可以了解这里的差异是什么?
import numpy as np
A = np.arange(12).reshape(4,3)
for a in A:
a = a + 1
B = np.arange(12).reshape(4,3)
for b in B:
b += 1
Run Code Online (Sandbox Code Playgroud)
运行每个for循环后,A没有更改,但B已经添加了一个元素.我实际上使用该B版本写入for循环内的初始化NumPy数组.
MSe*_*ert 112
不同之处在于,一个修改数据结构本身(就地操作),b += 1而另一个只是重新分配变量a = a + 1.
只是为了完整性:
x += y是不是总是做就地操作,有(至少)三种例外情况:
如果x 没有实现的__iadd__方法则x += y声明仅仅是一个速记x = x + y.如果x是类似的话就是这种情况int.
如果__iadd__返回NotImplemented,Python会回归x = x + y.
__iadd__理论上可以实施该方法以使其不起作用.但是,做到这一点真的很奇怪.
碰巧你的bs是numpy.ndarray实现__iadd__并返回自己的,所以你的第二个循环就地修改了原始数组.
您可以在"模拟数字类型"的Python文档中阅读更多相关内容.
这些[
__i*__]方法称为实现增强算术分配(+=,-=,*=,@=,/=,//=,%=,**=,<<=,>>=,&=,^=,|=).这些方法应该尝试就地执行操作(修改self)并返回结果(可能是,但不一定是self).如果未定义特定方法,则扩充分配将回退到常规方法.例如,如果x是带有__iadd__()方法的类的实例,x += y则等效于x = x.__iadd__(y).否则,x.__add__(y)并y.__radd__(x)考虑与评估一样x + y.在某些情况下,增强赋值可能会导致意外错误(请参阅为什么a_tuple[i] += ["item"]在添加时会引发异常?),但这种行为实际上是数据模型的一部分.
jmd*_*_dk 13
正如已经指出的那样,就地b += 1更新b,同时a = a + 1计算a + 1然后将名称分配a给结果(现在a不再引用一行A).
为了+=正确理解运算符,我们还需要理解可变对象和不可变对象的概念.考虑一下当我们遗漏时会发生什么.reshape:
C = np.arange(12)
for c in C:
c += 1
print(C) # [ 0 1 2 3 4 5 6 7 8 9 10 11]
Run Code Online (Sandbox Code Playgroud)
我们看到,C在没有更新,这意味着c += 1和c = c + 1是等价的.这是因为现在C是一维数组(C.ndim == 1),因此在迭代时C,每个整数元素被拉出并分配给c.
现在在Python中,整数是不可变的,这意味着不允许就地更新,有效地转换c += 1为c = c + 1,c现在指的是一个新的整数,不以C任何方式耦合.当你遍历重新整形的数组时,整个行(np.ndarray和/)一次被分配给b(和a)可变对象,这意味着你可以随意使用新的整数,当你这样做时就会发生这种情况a += 1.
应该说,虽然提到的+和+=是换货如上所述是相关的(并且非常一般都是这样),任何类型的可以实现他们就是了通过定义任何的方式__add__和__iadd__方法,分别.
短形式(a += 1)可以选择a就地修改,而不是创建一个表示总和的新对象并将其重新绑定回相同的名称(a = a + 1)。因此,短形式(a += 1)非常有效,因为它不一定需要制作一份a不同于的副本a = a + 1。
另外,即使它们输出相同的结果,请注意它们是不同的,因为它们是单独的运算符:+和+=