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 += 1es 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 by ahacer referencia al mismo objeto, cuando se utiliza +=en b, lo que realmente cambia b(y ave 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 bhace 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 bera 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 xy ytienen diferentes tipos , a continuación, x + yintenta llamar y.__radd__(x). Entonces, en el caso donde tienes
foo_instance += bar_instance
si Foono 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_instancees una subclase del tipo de foo_instance(por ejemplo issubclass(Bar, Foo)). El racional para esto es porque Bares en cierto sentido un objeto "nivel más alto" que Fooasí Bardebe recibir la opción de anular Fooel comportamiento 's.
+=actúa comoextend()en el caso de las listas.