# When is “i += x” different from “i = i + x” in Python?

Each Answer to this Q is separated by one/two green lines.

I was told that `+=` can have different effects than the standard notation of `i = i +`. Is there a case in which `i += 1` would be different from `i = i + 1`?

This depends entirely on the object `i`.

`+=` calls the `__iadd__` method (if it exists — falling back on `__add__` if it doesn’t exist) whereas `+` calls the `__add__` method1 or the `__radd__` method in a few cases2.

From an API perspective, `__iadd__` is supposed to be used for modifying mutable objects in place (returning the object which was mutated) whereas `__add__` should return a new instance of something. For immutable objects, both methods return a new instance, but `__iadd__` will put the new instance in the current namespace with the same name that the old instance had. This is why

``````i = 1
i += 1
``````

seems to increment `i`. In reality, you get a new integer and assign it “on top of” `i` — losing one reference to the old integer. In this case, `i += 1` is exactly the same as `i = i + 1`. But, with most mutable objects, it’s a different story:

As a concrete example:

``````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]
``````

compared to:

``````a = [1, 2, 3]
b = a
b = b + [1, 2, 3]
print a #[1, 2, 3]
print b #[1, 2, 3, 1, 2, 3]
``````

notice how in the first example, since `b` and `a` reference the same object, when I use `+=` on `b`, it actually changes `b` (and `a` sees that change too — After all, it’s referencing the same list). In the second case however, when I do `b = b + [1, 2, 3]`, this takes the list that `b` is referencing and concatenates it with a new list `[1, 2, 3]`. It then stores the concatenated list in the current namespace as `b` — With no regard for what `b` was the line before.

1In the expression `x + y`, if `x.__add__` isn’t implemented or if `x.__add__(y)` returns `NotImplemented` and `x` and `y` have different types, then `x + y` tries to call `y.__radd__(x)`. So, in the case where you have

`foo_instance += bar_instance`

if `Foo` doesn’t implement `__add__` or `__iadd__` then the result here is the same as

`foo_instance = bar_instance.__radd__(bar_instance, foo_instance)`

2In the expression `foo_instance + bar_instance`, `bar_instance.__radd__` will be tried before `foo_instance.__add__` if the type of `bar_instance` is a subclass of the type of `foo_instance` (e.g. `issubclass(Bar, Foo)`). The rationale for this is that `Bar` is in some sense a “higher-level” object than `Foo` so `Bar` should get the option of overriding `Foo`‘s behavior.

Under the covers, `i += 1` does something like this:

``````try:
except AttributeError:
``````

While `i = i + 1` does something like this:

``````i = i.__add__(1)
``````

This is a slight oversimplification, but you get the idea: Python gives types a way to handle `+=` specially, by creating an `__iadd__` method as well as an `__add__`.

The intention is that mutable types, like `list`, will mutate themselves in `__iadd__` (and then return `self`, unless you’re doing something very tricky), while immutable types, like `int`, will just not implement it.

For example:

``````>>> l1 = []
>>> l2 = l1
>>> l1 += 
>>> l2

``````

Because `l2` is the same object as `l1`, and you mutated `l1`, you also mutated `l2`.

But:

``````>>> l1 = []
>>> l2 = l1
>>> l1 = l1 + 
>>> l2
[]
``````

Here, you didn’t mutate `l1`; instead, you created a new list, `l1 + `, and rebound the name `l1` to point at it, leaving `l2` pointing at the original list.

(In the `+=` version, you were also rebinding `l1`, it’s just that in that case you were rebinding it to the same `list` it was already bound to, so you can usually ignore that part.)

Here is an example that directly compares `i += x` with `i = i + x`:

``````def foo(x):
x = x + 

def bar(x):
x += 

c = 
foo(c); # c is not changed
bar(c); # c is changed to [27, 42]
`````` The answers/resolutions are collected from stackoverflow, are licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0 .