Programing

'for'루프에서 i = i + 1과 i + = 1의 차이점은 무엇입니까?

crosscheck 2020. 8. 8. 10:39
반응형

'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 += 1c = c + 1동일합니다. 이는 이제 C1D 배열 ( C.ndim == 1)이기 때문에을 반복 할 때 C각 정수 요소가 뽑혀에 할당되기 때문 c입니다.

이제 Python에서 정수는 변경 불가능합니다. 즉, 내부 업데이트가 허용되지 않고 효과적으로으로 변환 c += 1됩니다 c = c + 1. 여기서는 어떤 식 으로든 결합되지 않은 새로운 정수를 c참조합니다 . 모양이 변경된 배열을 반복 할 때 전체 행 한 번 (and )에 할당됩니다. 개체 변경 가능한 객체입니다. 즉, 원하는대로 새 정수를 사용할 수 있습니다 .Cnp.ndarraybaa += 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.

참고URL : https://stackoverflow.com/questions/41446833/what-is-the-difference-between-i-i-1-and-i-1-in-a-for-loop

반응형