Python “for”循环中的 i = i + 1 和 i += 1 有什么区别?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/41446833/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What is the difference between i = i + 1 and i += 1 in a 'for' loop?
提问by Adam Fjeldsted
I found out a curious thing today and was wondering if somebody could shed some light into what the difference is here?
我今天发现了一件奇怪的事情,想知道是否有人可以阐明这里的区别?
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
After running each forloop, Ahas not changed, but Bhas had one added to each element. I actually use the Bversion to write to a initialized NumPy array within a forloop.
每次for循环运行后,A都没有改变,只是B每个元素都加了一个。我实际上使用该B版本在for循环中写入初始化的 NumPy 数组。
回答by MSeifert
The difference is that one modifies the data-structure itself (in-place operation) b += 1while the other just reassignsthe variable a = a + 1.
不同之处在于,一个修改数据结构本身(就地操作),b += 1而另一个只是重新分配变量a = a + 1。
Just for completeness:
只是为了完整性:
x += yis not alwaysdoing an in-place operation, there are (at least) three exceptions:
x += y是不是总是做就地操作,有(至少)三种例外情况:
If
xdoesn't implementan__iadd__method then thex += ystatement is just a shorthand forx = x + y. This would be the case ifxwas something like anint.If
__iadd__returnsNotImplemented, Python falls back tox = x + y.The
__iadd__method could theoretically be implemented to not work in place. It'd be really weird to do that, though.
如果
x没有实现的__iadd__则方法的x += y声明仅仅是一个速记x = x + y。如果这会出现这种情况x是类似的int。如果
__iadd__返回NotImplemented,Python 回退到x = x + y.该
__iadd__方法理论上可以实施到不工作。不过这样做真的很奇怪。
As it happens your bs are numpy.ndarrays which implements __iadd__and return itself so your second loop modifies the original array in-place.
碰巧您的bs 是numpy.ndarrays ,它实现__iadd__并返回自身,因此您的第二个循环就地修改了原始数组。
You can read more on this in the Python documentation of "Emulating Numeric Types".
您可以在Python 文档“模拟数字类型”中阅读更多相关信息。
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 += yis equivalent tox = x.__iadd__(y). Otherwise,x.__add__(y)andy.__radd__(x)are considered, as with the evaluation ofx + y. In certain situations, augmented assignment can result in unexpected errors (see Why doesa_tuple[i] += ["item"]raise an exception when the addition works?), but this behavior is in fact part of the data model.
__i*__调用这些 [ ] 方法来实现增强算术赋值(+=、-=、*=、@=、/=、//=、%=、**=、<<=、>>=、&=、^=、|=)。这些方法应该尝试就地执行操作(修改 self)并返回结果(可以是但不一定是 self)。如果未定义特定方法,则增广赋值回退到正常方法。例如,如果 x 是具有__iadd__()方法的类的实例,x += y则等效于x = x.__iadd__(y)。否则,x.__add__(y)和y.__radd__(x)被考虑,与 的评估一样x + y。在某些情况下,扩充分配可能会导致意外错误(请参阅为什么a_tuple[i] += ["item"]添加工作时会引发异常?),但这种行为实际上是数据模型的一部分。
回答by Maroun
In the first example, you are reassigning the variable a, while in the second one you are modifying the data in-place, using the +=operator.
在第一个示例中,您正在重新分配变量a,而在第二个示例中,您正在使用+=运算符就地修改数据。
See the section about 7.2.1. Augmented assignment statements :
An augmented assignment expression like
x += 1can be rewritten asx = x + 1to 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.
x += 1可以重写x = x + 1类似的增强赋值表达式以实现类似但不完全相同的效果。在增强版本中,x 只计算一次。此外,在可能的情况下,实际操作是就地执行的,这意味着不是创建新对象并将其分配给目标,而是修改旧对象。
+=operator calls __iadd__. This function makes the change in-place, and only after its execution, the result is set back to the object you are "applying" the +=on.
+=接线员调用__iadd__。此函数进行就地更改,只有在执行后,结果才会设置回您正在“应用”的对象+=。
__add__on the other hand takes the parameters and returns their sum (without modifying them).
__add__另一方面,获取参数并返回它们的总和(不修改它们)。
回答by jmd_dk
As already pointed out, b += 1updates bin-place, while a = a + 1computes a + 1and then assigns the name ato the result (now adoes not refer to a row of Aanymore).
正如已经指出的那样,就地b += 1更新b,而a = a + 1计算a + 1然后将名称分配a给结果(现在a不再引用一行A)。
To understand the +=operator properly though, we need also to understand the concept of mutableversus immutableobjects. Consider what happens when we leave out the .reshape:
+=不过,要正确理解运算符,我们还需要了解可变对象与不可变对象的概念。考虑一下当我们省略 时会发生什么.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]
We see that Cis notupdated, meaning that c += 1and c = c + 1are equivalent. This is because now Cis a 1D array (C.ndim == 1), and so when iterating over C, each integer element is pulled out and assigned to c.
我们看到,C在没有更新,这意味着c += 1和c = c + 1是等价的。这是因为 nowC是一个一维数组 ( C.ndim == 1),因此在迭代 时C,每个整数元素都会被拉出并分配给c。
Now in Python, integers are immutable, meaning that in-place updates are not allowed, effectively transforming c += 1into c = c + 1, where cnow refers to a newinteger, not coupled to Cin any way. When you loop over the reshaped arrays, whole rows (np.ndarray's) are assigned to b(and a) at a time, which are mutableobjects, meaning that you are allowed to stick in new integers at will, which happens when you do a += 1.
现在在 Python 中,整数是不可变的,这意味着不允许就地更新,有效地转换c += 1为c = c + 1,其中cnow 指的是一个新整数,不以C任何方式耦合。当您循环重整数组时,整行 ( np.ndarray's) 一次被分配给b(and a),它们是可变对象,这意味着您可以随意插入新整数,这在您执行a += 1.
It should be mentioned that though +and +=are meant to be related as described above (and very much usually are), any type can implement them any way it wants by defining the __add__and __iadd__methods, respectively.
应该提到的是,尽管+和+=如上所述(并且通常是)相关联,但任何类型都可以通过分别定义__add__和__iadd__方法来以任何方式实现它们。
回答by Inconnu
The short form(a += 1) has the option to modify ain-place , instead of creating a new object representing the sum and rebinding it back to the same name(a = a + 1).So,The short form(a += 1) is much efficient as it doesn't necessarily need to make a copy of aunlike a = a + 1.
短格式( a += 1) 可以选择a就地修改,而不是创建一个表示总和的新对象并将其重新绑定回相同的名称( a = a + 1)。因此,短格式( a += 1) 非常有效,因为它不一定需要制作一个a不同的副本a = a + 1。
Also even if they are outputting the same result, notice they are different because they are separate operators: +and +=
此外,即使它们输出相同的结果,请注意它们是不同的,因为它们是单独的运算符:+和+=
回答by Andi Kleve
First off: The variables a and b in the loops refer to numpy.ndarrayobjects.
首先:循环中的变量 a 和 b 指的是numpy.ndarray对象。
In the first loop, a = a + 1is evaluated as follows: the __add__(self, other)function of numpy.ndarrayis called. This creates a new object and hence, A is not modified. Afterwards, the variable ais set to refer to the result.
在第一个循环中,a = a + 1评估如下:调用的__add__(self, other)函数numpy.ndarray。这会创建一个新对象,因此不会修改 A。之后,变量a被设置为引用结果。
In the second loop, no new object is created. The statement b += 1calls the __iadd__(self, other)function of numpy.ndarraywhich modifies the ndarrayobject in place to which b is referring to. Hence, Bis modified.
在第二个循环中,没有创建新对象。该语句b += 1调用which的__iadd__(self, other)函数numpy.ndarray修改ndarrayb 所指的对象。因此,B被修改。
回答by hpaulj
A key issue here is that this loop iterates over the rows (1st dimension) of B:
这里的一个关键问题是此循环迭代 的行(第一维)B:
In [258]: B
Out[258]:
array([[ 0, 1, 2],
[ 3, 4, 5],
[ 6, 7, 8],
[ 9, 10, 11]])
In [259]: for b in B:
...: print(b,'=>',end='')
...: b += 1
...: print(b)
...:
[0 1 2] =>[1 2 3]
[3 4 5] =>[4 5 6]
[6 7 8] =>[7 8 9]
[ 9 10 11] =>[10 11 12]
Thus the +=is acting on a mutable object, an array.
因此+=作用于一个可变对象,一个数组。
This is implied in the other answers, but easily missed if your focus is on the a = a+1reassignment.
这在其他答案中有所暗示,但如果您的重点是a = a+1重新分配,则很容易错过。
I could also make an in-place change to bwith [:]indexing, or even something fancier, b[1:]=0:
我也可以做一个就地变化b与[:]索引,甚至一些票友,b[1:]=0:
In [260]: for b in B:
...: print(b,'=>',end='')
...: b[:] = b * 2
[1 2 3] =>[2 4 6]
[4 5 6] =>[ 8 10 12]
[7 8 9] =>[14 16 18]
[10 11 12] =>[20 22 24]
Of course with a 2d array like Bwe usually don't need to iterate on the rows. Many operations that work on a single of Balso work on the whole thing. B += 1, B[1:] = 0, etc.
当然,对于二维数组,B我们通常不需要对行进行迭代。许多对单个B事物起作用的操作也对整个事物起作用。 B += 1,B[1:] = 0等等。

