Isso depende inteiramente do objeto i
.
+=
chama o __iadd__
método (se existir - recorrendo novamente __add__
se não existir), enquanto +
chama o __add__
método 1 ou o __radd__
método em alguns casos 2 .
Do ponto de vista da API, __iadd__
é suposto ser usado para modificar objetos mutáveis no local (retornando o objeto que foi mutado), ao passo que __add__
deve retornar uma nova instância de algo. Para objetos imutáveis , os dois métodos retornam uma nova instância, mas __iadd__
colocam a nova instância no espaço para nome atual com o mesmo nome que a instância antiga. Isso é por que
i = 1
i += 1
parece aumentar i
. Na realidade, você obtém um novo número inteiro e o atribui "em cima de" i
- perdendo uma referência ao número inteiro antigo. Nesse caso, i += 1
é exatamente o mesmo que i = i + 1
. Mas, com a maioria dos objetos mutáveis, é uma história diferente:
Como um exemplo concreto:
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]
comparado com:
a = [1, 2, 3]
b = a
b = b + [1, 2, 3]
print a #[1, 2, 3]
print b #[1, 2, 3, 1, 2, 3]
Observe como no primeiro exemplo, uma vez b
e a
referenciar o mesmo objeto, quando eu uso +=
em b
, ele realmente muda b
(e a
vê que a mudança também - Afinal de contas, ele está referenciando a mesma lista). No segundo caso, no entanto, quando eu faço b = b + [1, 2, 3]
, isso pega a lista que b
está fazendo referência e a concatena com uma nova lista [1, 2, 3]
. Em seguida, ele armazena a lista concatenada no espaço para nome atual como b
- Sem levar em conta qual b
era a linha anterior.
1 Na expressão x + y
, se x.__add__
não for implementada ou se x.__add__(y)
retorna NotImplemented
e x
e y
têm tipos diferentes , em seguida, x + y
tenta chamar y.__radd__(x)
. Então, no caso em que você tem
foo_instance += bar_instance
se Foo
não implementar __add__
ou __iadd__
então o resultado aqui é o mesmo que
foo_instance = bar_instance.__radd__(bar_instance, foo_instance)
2 Na expressão foo_instance + bar_instance
, bar_instance.__radd__
será tentado antes foo_instance.__add__
se o tipo de bar_instance
for uma subclasse do tipo de foo_instance
(por exemplo issubclass(Bar, Foo)
). O racional para isso é porque Bar
é em certo sentido um objeto "de alto nível" que Foo
assim Bar
deve obter a opção de substituir Foo
o comportamento.
+=
age comoextend()
no caso de listas.