Esto depende completamente del objeto i
.
+=
llama al __iadd__
método (si existe, recurriendo __add__
si no existe) mientras que +
llama al __add__
método 1 o al __radd__
método en algunos casos 2 .
Desde una perspectiva API, __iadd__
se supone que se usa para modificar objetos mutables en su lugar (devolviendo el objeto que fue mutado), mientras que __add__
debería devolver una nueva instancia de algo. Para los objetos inmutables , ambos métodos devuelven una nueva instancia, pero __iadd__
colocarán la nueva instancia en el espacio de nombres actual con el mismo nombre que tenía la instancia anterior. Esta es la razón por
i = 1
i += 1
Parece aumentar i
. En realidad, obtienes un nuevo entero y lo asignas "encima" i
, perdiendo una referencia al entero anterior. En este caso, i += 1
es exactamente lo mismo que i = i + 1
. Pero, con la mayoría de los objetos mutables, es una historia diferente:
Como ejemplo 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 con:
a = [1, 2, 3]
b = a
b = b + [1, 2, 3]
print a #[1, 2, 3]
print b #[1, 2, 3, 1, 2, 3]
Nótese como en el primer ejemplo, puesto b
y a
hacer referencia al mismo objeto, cuando se utiliza +=
en b
, lo que realmente cambia b
(y a
ve que el cambio también - Después de todo, se hace referencia a la misma lista). Sin embargo, en el segundo caso, cuando lo hago b = b + [1, 2, 3]
, toma la lista que b
hace referencia y la concatena con una nueva lista [1, 2, 3]
. Luego almacena la lista concatenada en el espacio de nombres actual como b
: sin tener en cuenta cuál b
era la línea anterior.
1 En la expresión x + y
, si x.__add__
no se ejecuta o si x.__add__(y)
vuelve NotImplemented
y x
y y
tienen diferentes tipos , a continuación, x + y
intenta llamar y.__radd__(x)
. Entonces, en el caso donde tienes
foo_instance += bar_instance
si Foo
no se implementa __add__
o __iadd__
el resultado aquí es el mismo que
foo_instance = bar_instance.__radd__(bar_instance, foo_instance)
2 En la expresión foo_instance + bar_instance
, bar_instance.__radd__
se intentará antes foo_instance.__add__
si el tipo de bar_instance
es una subclase del tipo de foo_instance
(por ejemplo issubclass(Bar, Foo)
). El racional para esto es porque Bar
es en cierto sentido un objeto "nivel más alto" que Foo
así Bar
debe recibir la opción de anular Foo
el comportamiento 's.
+=
actúa comoextend()
en el caso de las listas.