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 be areferenciar o mesmo objeto, quando eu uso +=em b, ele realmente muda b(e avê 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 bestá 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 bera a linha anterior.
1 Na expressão x + y, se x.__add__não for implementada ou se x.__add__(y)retorna NotImplemented e xe ytêm tipos diferentes , em seguida, x + ytenta chamar y.__radd__(x). Então, no caso em que você tem
foo_instance += bar_instance
se Foonã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_instancefor 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 Fooassim Bardeve obter a opção de substituir Fooo comportamento.
+=age comoextend()no caso de listas.