在“for”循环中,i=i+1和i+=1之间的区别是什么?

2024-04-26 05:18:01 发布

您现在位置:Python中文网/ 问答频道 /正文

我今天发现了一件奇怪的事情,想知道是否有人能解释一下这里有什么不同?

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数组。


Tags: inimport版本numpy元素forasnp
3条回答

如前所述,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]

我们看到C而不是更新,这意味着c += 1c = c + 1是等价的。这是因为现在C是一个1D数组(C.ndim == 1),所以当在C上迭代时,每个整数元素都被拉出并分配给c

现在在Python中,整数是不可变的,这意味着不允许就地更新,有效地将c += 1转换为c = c + 1,其中c现在指的是一个不以任何方式耦合到C新的整数。当您循环经过整形的数组时,整行(np.ndarray)一次被分配给b(和a),这是可改变的对象,这意味着您可以随意插入新整数,这在您执行a += 1时发生。

应该提到的是,尽管++=是如上所述相关的(而且通常是相关的),但是任何类型都可以通过分别定义__add__^{}方法以任何方式实现它们。

在第一个示例中,您正在重新分配变量a,而在第二个示例中,您正在使用+=运算符就地修改数据。

请参阅有关7.2.1. Augmented assignment statements 的部分:

An augmented assignment expression like x += 1 can be rewritten as x = x + 1 to achieve a similar, but not exactly equal effect. In the augmented version, x is only evaluated once. Also, when possible, the actual operation is performed in-place, meaning that rather than creating a new object and assigning that to the target, the old object is modified instead.

+=运算符调用^{}。此函数就地进行更改,只有在执行之后,结果才会被设置回您正在“应用”的+=对象。

另一方面,^{}接受参数并返回它们的和(不修改它们)。

不同之处在于,一个修改数据结构本身(就地操作)b += 1,而另一个只是重新分配变量a = a + 1


为了完整起见:

x += y如果不总是执行就地操作,则(至少)有三个例外:

  • 如果x没有实现__iadd__方法,那么x += y语句只是x = x + y的简写。如果xint类似,就会出现这种情况。

  • 如果__iadd__返回NotImplemented,Python将返回x = x + y

  • 从理论上讲,__iadd__方法可以实现为不工作。不过,那样做真的很奇怪。

实际上,您的bs是实现__iadd__并返回自身的numpy.ndarrays,因此您的第二个循环将修改原始数组。

你可以在Python documentation of "Emulating Numeric Types"中阅读更多关于这个的内容。

These [__i*__] methods are called to implement the augmented arithmetic assignments (+=, -=, *=, @=, /=, //=, %=, **=, <<=, >>=, &=, ^=, |=). These methods should attempt to do the operation in-place (modifying self) and return the result (which could be, but does not have to be, self). If a specific method is not defined, the augmented assignment falls back to the normal methods. For instance, if x is an instance of a class with an __iadd__() method, x += y is equivalent to x = x.__iadd__(y) . Otherwise, x.__add__(y) and y.__radd__(x) are considered, as with the evaluation of x + y. In certain situations, augmented assignment can result in unexpected errors (see Why does a_tuple[i] += ["item"] raise an exception when the addition works?), but this behavior is in fact part of the data model.

相关问题 更多 >