'for'루프에서 i = i + 1과 i + = 1의 차이점은 무엇입니까? [복제]
이 질문에 이미 답변이 있습니다.
나는 오늘 궁금한 것을 발견하고 누군가가 여기에 차이점이 무엇인지에 대해 밝힐 수 있는지 궁금합니다.
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
내에서 초기화 된 NumPy 배열에 쓰기 위해 버전을 사용합니다 for
.
차이점은 하나는 데이터 구조 자체를 수정하고 (제자리 작업) b += 1
다른 하나 는 변수를 재 할당 한다는 것입니다 a = a + 1
.
완전성을 위해 :
x += y
항상 제자리 작업을 수행하는 것은 아니며 최소한 세 가지 예외가 있습니다.
만약이
x
구현하지 않는__iadd__
방법은 다음x += y
문이 단지 속기이다x = x + y
. 경우에 해당 될 것이다x
같은했다int
.경우
__iadd__
반환NotImplemented
, 파이썬은 다시 폭포x = x + y
.이
__iadd__
방법은 이론적으로 제자리에서 작동하지 않도록 구현할 수 있습니다. 하지만 그렇게하면 정말 이상 할 것입니다.
공교롭게도 당신 b
의은 numpy.ndarray
구현의 __iadd__
두 번째 루프 수정 있도록 현재 위치에서 원래 배열 자체를 반환하고.
이에 대한 자세한 내용 은 "Emulating Numeric Types"Python 문서 에서 확인할 수 있습니다 .
이러한 [
__i*__
]의 방법이 증가 된 연산 할당을 구현하도록 부름 (+=
,-=
,*=
,@=
,/=
,//=
,%=
,**=
,<<=
,>>=
,&=
,^=
,|=
). 이러한 메서드는 작업을 제자리에서 수행하고 (자체 수정) 결과를 반환해야합니다 (자체 일 수 있지만 반드시 그럴 필요는 없음). 특정 방법이 정의되지 않은 경우 확장 할당은 일반 방법으로 대체됩니다. x가 클래스의 인스턴스와는 경우 예를 들어,__iadd__()
방법x += y
동등x = x.__iadd__(y)
. 그렇지 않으면,x.__add__(y)
그리고y.__radd__(x)
평가와 마찬가지로 간주됩니다x + y
. 특정 상황에서 증가 된 할당으로 인해 예기치 않은 오류가 발생할 수 있습니다 (참조 :a_tuple[i] += ["item"]
추가가 작동 할 때 예외가 발생하는 이유는 무엇 입니까? ), 그러나이 동작은 실제로 데이터 모델의 일부입니다.
첫 번째 예에서는 변수를 다시 할당하고 a
두 번째 예에서는 +=
연산자를 사용하여 데이터를 제자리에서 수정합니다 .
7.2.1에 대한 섹션을 참조하십시오 . 증강 할당 문 :
유사하지만 정확히 동일한 효과를 얻기 위해 다음과 같은 증강 할당 표현식을
x += 1
다시 작성할 수 있습니다x = x + 1
. 증강 버전에서 x는 한 번만 평가됩니다. 또한 가능한 경우 실제 작업이 제자리에서 수행됩니다 . 즉, 새 개체를 만들어 대상에 할당하는 대신 이전 개체가 수정됩니다.
+=
운영자 호출 __iadd__
. 이 함수는 제자리에서 변경을 수행하고 실행 후에 만 결과가 "적용"중인 개체로 다시 설정 +=
됩니다.
__add__
반면에 매개 변수를 가져 와서 수정하지 않고 합계를 반환합니다.
이미 지적했듯이, 제자리에서 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 += 1
와 c = c + 1
동일합니다. 이는 이제 C
1D 배열 ( C.ndim == 1
)이기 때문에을 반복 할 때 C
각 정수 요소가 뽑혀에 할당되기 때문 c
입니다.
이제 Python에서 정수는 변경 불가능합니다. 즉, 내부 업데이트가 허용되지 않고 효과적으로으로 변환 c += 1
됩니다 c = c + 1
. 여기서는 어떤 식 으로든 결합되지 않은 새로운 정수를 c
참조합니다 . 모양이 변경된 배열을 반복 할 때 전체 행 이 한 번 에 (and )에 할당됩니다. 이 개체 는 변경 가능한 객체입니다. 즉, 원하는대로 새 정수를 사용할 수 있습니다 .C
np.ndarray
b
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.
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
.
Also even if they are outputting the same result, notice they are different because they are separate operators: +
and +=
First off: The variables a and b in the loops refer to numpy.ndarray
objects.
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.
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.
A key issue here is that this loop iterates over the rows (1st dimension) of 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.
I could also make an in-place change to b
with [:]
indexing, or even something fancier, 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.
'Programing' 카테고리의 다른 글
루비에서 환원과 같은 것을 주입합니까? (0) | 2020.08.08 |
---|---|
GSON을 사용하여 JSON 배열 구문 분석 (0) | 2020.08.08 |
정적 클래스 초기화는 언제 발생합니까? (0) | 2020.08.08 |
이 코드가 64 비트 아키텍처에서는 segfault이지만 32 비트에서는 잘 작동하는 이유는 무엇입니까? (0) | 2020.08.08 |
DESTDIR 및 PREFIX of make (0) | 2020.08.08 |