[python] 파이썬에서 “i + = x”는 “i = i + x”와 언제 다릅니 까?

나는 +=표준 표기법과는 다른 효과를 가질 수 있다고 들었습니다 i = i +. 하는 경우가 i += 1다른 것은 i = i + 1?



답변

이것은 전적으로 객체에 의존합니다 i.

+=__iadd__메소드를 호출합니다 (존재하는 경우- __add__존재하지 않는 경우 폴백) +. __add__메소드 1 또는 메소드를 호출하는 __radd__경우가 있습니다 2 .

API 관점에서 볼 때 __iadd__변경 가능한 객체를 수정 (변경된 객체 반환)하는 데 사용되는 반면 새로운 인스턴스__add__반환해야 합니다. 들어 불변의 객체, 두 가지 방법은 새로운 인스턴스를 반환하지만, 이전 인스턴스가 가진 것과 같은 이름으로 현재 네임 스페이스의 새로운 인스턴스를 둘 것이다. 이는 이유__iadd__

i = 1
i += 1

증가하는 것 같습니다 i. 실제로 새 정수를 가져 와서 “정수”에 할당 i하면 이전 정수에 대한 하나의 참조가 손실됩니다. 이 경우와 i += 1정확히 동일합니다 i = i + 1. 그러나 가장 가변적 인 객체의 경우 다른 이야기입니다.

구체적인 예로서 :

a = [1, 2, 3]
b = a
b += [1, 2, 3]
print a  #[1, 2, 3, 1, 2, 3]
print b  #[1, 2, 3, 1, 2, 3]

다음과 비교 :

a = [1, 2, 3]
b = a
b = b + [1, 2, 3]
print a #[1, 2, 3]
print b #[1, 2, 3, 1, 2, 3]

on을 사용할 때 첫 번째 예제 에서 동일한 객체를 참조 b하고 a참조하면 실제로 변경됩니다 (그리고 그 변경 사항도 볼 수 있습니다-결국 동일한 목록을 참조합니다). 그러나 두 번째 경우, 내가 할 때 이것은 참조 하는 목록을 가져 와서 새로운 목록과 연결합니다 . 그 다음으로 현재 이름 공간에 연결된 목록을 저장 – 무엇에 대한 어떤 관련하여 이전에 선이었다.+=bbab = b + [1, 2, 3]b[1, 2, 3]bb


1 발현은 x + y, 경우는 x.__add__구현되지 않은 경우 또는 x.__add__(y)반환 NotImplemented x와는 y다른 유형을 가지고 , 다음 x + y호출을 시도합니다 y.__radd__(x). 그래서, 당신이 가진 경우

foo_instance += bar_instance

경우 Foo구현하지 않는 __add__또는 __iadd__여기에 결과는 동일하다

foo_instance = bar_instance.__radd__(bar_instance, foo_instance)

식에서는 foo_instance + bar_instance, bar_instance.__radd__이전에 시도 될 foo_instance.__add__ 경우 의 타입 bar_instance의 유형의 서브 클래스 foo_instance(예 issubclass(Bar, Foo)). 이에 대한 합리적인 이유 Bar는 어떤 의미에서는 “상위 레벨”객체이기 Foo때문에 동작 Bar을 재정의하는 옵션을 가져와야하기 때문 Foo입니다.


답변

표지 아래에서 i += 1다음과 같이하십시오.

try:
    i = i.__iadd__(1)
except AttributeError:
    i = i.__add__(1)

하지만이 i = i + 1같은 무언가를 :

i = i.__add__(1)

이것은 약간 지나치게 단순화되었지만 아이디어를 얻습니다. 파이썬은 유형 뿐만 아니라 메소드를 +=작성하여 특수하게 처리 할 수있는 __iadd__방법을 제공합니다 __add__.

의도는와 같은 가변 유형 list은 스스로 변이하고 __iadd__( self매우 까다로운 작업을 수행하지 않으면 return ),과 같은 불변 유형 int은 구현하지 않을 것입니다.

예를 들면 다음과 같습니다.

>>> l1 = []
>>> l2 = l1
>>> l1 += [3]
>>> l2
[3]

때문에 l2같은 객체이다 l1, 당신은 돌연변이 l1, 당신은 또한 돌연변이 l2.

그러나:

>>> l1 = []
>>> l2 = l1
>>> l1 = l1 + [3]
>>> l2
[]

여기, 당신은 돌연변이하지 않았다 l1; 대신 새 목록 인을 만들고 원래 목록을 가리키면서 l1 + [3]이름 l1을 리바운드 l2합니다.

( +=버전 에서는 리 바인드 l1했습니다.이 경우 list이미 바인딩 된 것과 동일 하게 리 바인드 했기 때문에 일반적으로 해당 부분을 무시할 수 있습니다.)


답변

여기서 직접 비교 예이다 i += x으로는 i = i + x:

def foo(x):
  x = x + [42]

def bar(x):
  x += [42]

c = [27]
foo(c); # c is not changed
bar(c); # c is changed to [27, 42]


답변