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 for
loop, A
has not changed, but B
has had one added to each element. I actually use the B
version to write to a initialized NumPy array within a for
loop.
每次for
循环运行后,A
都没有改变,只是B
每个元素都加了一个。我实际上使用该B
版本在for
循环中写入初始化的 NumPy 数组。
回答by MSeifert
The difference is that one modifies the data-structure itself (in-place operation) b += 1
while the other just reassignsthe variable a = a + 1
.
不同之处在于,一个修改数据结构本身(就地操作),b += 1
而另一个只是重新分配变量a = a + 1
。
Just for completeness:
只是为了完整性:
x += y
is not alwaysdoing an in-place operation, there are (at least) three exceptions:
x += y
是不是总是做就地操作,有(至少)三种例外情况:
If
x
doesn't implementan__iadd__
method then thex += y
statement is just a shorthand forx = x + y
. This would be the case ifx
was 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 b
s are numpy.ndarray
s which implements __iadd__
and return itself so your second loop modifies the original array in-place.
碰巧您的b
s 是numpy.ndarray
s ,它实现__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 += y
is 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 += 1
can be rewritten asx = 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.
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 += 1
updates b
in-place, while a = a + 1
computes a + 1
and then assigns the name a
to the result (now a
does not refer to a row of A
anymore).
正如已经指出的那样,就地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 C
is notupdated, meaning that c += 1
and c = c + 1
are equivalent. This is because now C
is 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 += 1
into c = c + 1
, where c
now refers to a newinteger, not coupled to C
in 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
,其中c
now 指的是一个新整数,不以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 a
in-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 a
unlike 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.ndarray
objects.
首先:循环中的变量 a 和 b 指的是numpy.ndarray
对象。
In the first loop, a = a + 1
is evaluated as follows: the __add__(self, other)
function of numpy.ndarray
is called. This creates a new object and hence, A is not modified. Afterwards, the variable a
is 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 += 1
calls the __iadd__(self, other)
function of numpy.ndarray
which modifies the ndarray
object in place to which b is referring to. Hence, B
is modified.
在第二个循环中,没有创建新对象。该语句b += 1
调用which的__iadd__(self, other)
函数numpy.ndarray
修改ndarray
b 所指的对象。因此,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+1
reassignment.
这在其他答案中有所暗示,但如果您的重点是a = a+1
重新分配,则很容易错过。
I could also make an in-place change to b
with [:]
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 B
we usually don't need to iterate on the rows. Many operations that work on a single of B
also work on the whole thing. B += 1
, B[1:] = 0
, etc.
当然,对于二维数组,B
我们通常不需要对行进行迭代。许多对单个B
事物起作用的操作也对整个事物起作用。 B += 1
,B[1:] = 0
等等。