我今天发现了一件奇怪的事情,想知道是否有人可以阐明其中的区别?
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
运行完每个for循环后,A没有改变,但是B在每个元素中添加了一个。我实际上使用该B版本在for循环内写入初始化的NumPy数组。
for
A
B
不同之处在于,一个修改数据结构本身(就地操作),b += 1而另一个仅 重新分配 变量a = a + 1。
b += 1
a = a + 1
仅出于完整性考虑:
x += y是 不是总是 做就地操作,有(至少)三种例外情况:
x += y
如果x 没有实现 的__iadd__则方法的x += y声明仅仅是一个速记x = x + y。如果x是类似的情况就是这种情况int。
x
__iadd__
x = x + y
int
如果__iadd__返回NotImplemented,Python将退回到x = x + y。
NotImplemented
从__iadd__理论上讲,该方法可以实现为无法正常运行。但是,这样做真的很奇怪。
发生时,您的bs是numpy.ndarray实现__iadd__并返回自身的,因此您的第二个循环就地修改了原始数组。
b
numpy.ndarray
您可以在Python文档“模拟数字类型”中了解更多信息。
这些[ __i*__]方法称为实现增强算术分配(+=,-=,*=,@=,/=,//=,%=,**=,<<=,>>=,&=,^=,|=)。这些方法应尝试就地执行操作(修改self)并返回结果(可以是,但不一定是self)。如果未定义特定方法,则扩展分配将退回到常规方法。例如,如果x是具有__iadd__()方法的类的实例,x += y则等效于x = x.__iadd__(y)。否则,将x.__add__(y)与和y.__radd__(x)一起评估x + y。在某些情况下,扩充分配可能会导致意外错误(请参见为什么a_tuple[i] += ["item"]加法有效时会引发异常?),但实际上,该行为是数据模型的一部分。
__i*__
+=
-=
*=
@=
/=
//=
%=
**=
<<=
>>=
&=
^=
|=
__iadd__()
x = x.__iadd__(y)
x.__add__(y)
y.__radd__(x)
x + y
a_tuple[i] += ["item"]