나는 +=
표준 표기법과는 다른 효과를 가질 수 있다고 들었습니다 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
참조하면 실제로 변경됩니다 (그리고 그 변경 사항도 볼 수 있습니다-결국 동일한 목록을 참조합니다). 그러나 두 번째 경우, 내가 할 때 이것은 참조 하는 목록을 가져 와서 새로운 목록과 연결합니다 . 그 다음으로 현재 이름 공간에 연결된 목록을 저장 – 무엇에 대한 어떤 관련하여 이전에 선이었다.+=
b
b
a
b = b + [1, 2, 3]
b
[1, 2, 3]
b
b
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]