Questo dipende interamente dall'oggetto i
.
+=
chiama il __iadd__
metodo (se esiste - riconnettendosi __add__
se non esiste) mentre +
chiama il __add__
metodo 1 o il __radd__
metodo in alcuni casi 2 .
Dal punto di vista dell'API, __iadd__
dovrebbe essere usato per modificare gli oggetti mutabili sul posto (restituendo l'oggetto che è stato mutato) mentre __add__
dovrebbe restituire una nuova istanza di qualcosa. Per oggetti immutabili , entrambi i metodi restituiscono una nuova istanza, ma __iadd__
inseriranno la nuova istanza nello spazio dei nomi corrente con lo stesso nome della vecchia istanza. Ecco perché
i = 1
i += 1
sembra aumentare i
. In realtà, ottieni un nuovo numero intero e lo assegni "sopra" i
- perdendo un riferimento al vecchio numero intero. In questo caso, i += 1
è esattamente lo stesso di i = i + 1
. Ma, con la maggior parte degli oggetti mutabili, è una storia diversa:
A titolo di esempio 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]
rispetto a:
a = [1, 2, 3]
b = a
b = b + [1, 2, 3]
print a #[1, 2, 3]
print b #[1, 2, 3, 1, 2, 3]
nota come nel primo esempio, dato che b
e a
riferimento allo stesso oggetto, quando lo uso +=
su b
, in realtà cambia b
(e a
vede anche quel cambiamento - Dopotutto, fa riferimento allo stesso elenco). Nel secondo caso, tuttavia, quando lo faccio b = b + [1, 2, 3]
, prende l'elenco che b
fa riferimento e lo concatena con un nuovo elenco [1, 2, 3]
. Quindi memorizza l'elenco concatenato nello spazio dei nomi corrente come b
- Senza riguardo a quella che b
era la linea prima.
1 Nell'espressione x + y
, se x.__add__
non è attuato o se x.__add__(y)
i rendimenti NotImplemented
e x
ed y
hanno tipi diversi , quindi x + y
tenta di chiamare y.__radd__(x)
. Quindi, nel caso in cui tu abbia
foo_instance += bar_instance
se Foo
non implementa __add__
o __iadd__
quindi il risultato qui è lo stesso di
foo_instance = bar_instance.__radd__(bar_instance, foo_instance)
2 Nell'espressione foo_instance + bar_instance
, bar_instance.__radd__
verrà provato prima foo_instance.__add__
se il tipo di bar_instance
è una sottoclasse del tipo di foo_instance
(ad es issubclass(Bar, Foo)
.). Il razionale di questo è perché Bar
è in un certo senso un oggetto "di livello superiore" rispetto Foo
così Bar
dovrebbe ottenere la possibilità di sovrascrivere Foo
's comportamento.
+=
si comporta comeextend()
in caso di liste.