In Python, is there any difference (semantics, efficiency, etc.) between writing x = x+1
and x += 1
?
4 Answers
Yes. Depending on how the class of x
is coded, the short form has the option to modify x in-place, instead of creating a new object representing the sum and rebinding it back to the same name. This has an implication if you have multiple variables all referring to the same object - eg, with lists:
>>> a = b = []
>>> a += [5]
>>> a
[5]
>>> b
[5]
>>> a = a + [5]
>>> a
[5, 5]
>>> b
[5]
This happens because behind the scenes, the operators call different magic methods: +
calls __add__
or __radd__
(which are expected not to modify either of their arguments) and +=
tries __iadd__
(which is allowed to modify self
if it feels like it) before falling back to the +
logic if __iadd__
isn't there.

- 260,549
- 28
- 431
- 505

- 34,233
- 10
- 73
- 98
They are almost same for integers and floats, but for lists
:
lis = lis+['foo']
creates a new list by concatenating lis
and ['foo']
and then assigns the result to lis
and :
lis += [foo]
is equivalent to lis.extend([foo])
>>> lis = [1,2,3]
>>> id(lis)
3078880140L
>>> lis += ['foo'] #or lis.extend(['foo'])
>>> id(lis) #same object
3078880140L
>>> lis = [1,2,3]
>>> id(lis)
3078880076L
>>> lis = lis+['foo']
>>> id(lis) #new object
3078880012L

- 244,495
- 58
- 464
- 504
Yes, they are different operators that compile to different bytecode:
>>> import dis
>>> def test1(x):
... x = x + 1
...
>>> def test2(x):
... x += 1
...
>>> dis.dis(test1)
2 0 LOAD_FAST 0 (x)
3 LOAD_CONST 1 (1)
6 BINARY_ADD
7 STORE_FAST 0 (x)
10 LOAD_CONST 0 (None)
13 RETURN_VALUE
>>> dis.dis(test2)
2 0 LOAD_FAST 0 (x)
3 LOAD_CONST 1 (1)
6 INPLACE_ADD
7 STORE_FAST 0 (x)
10 LOAD_CONST 0 (None)
13 RETURN_VALUE
In this case, it won't make a huge difference as int
s are immutable. In theory they could be implemented in different ways (depending on the interpreter), but that won't change the way it operates on the value.
In general, they can be implemented to do completely different things (+
being implemented by the magic method __add__()
and +=
with __iadd()__
) - in most mutable containers, for example, it makes a huge difference, if you have different names referencing the same object:
>>> x = []
>>> y = x
>>> x += [1]
>>> y
[1]
>>> x = x + [1]
>>> y
[1]
>>> x
[1, 1]
You can see that when we assign x
to y
, they both point to the same list. When we use +=
, we extend the list and both change. When we assign a new value to x
, y
still points to the original and remains unchanged.

- 86,389
- 17
- 178
- 183
They are different because there are seperate operators for +
and +=
. With x = x + 1
, the interpreter will treat it like x = x.__add__(1)
, while x += 1
will be x = x.__iadd(1)
, which can be much more efficient because it doesn't necessarily need to make a copy of x
.

- 53,280
- 21
- 146
- 188
-
`x += 1` actually becomes `x = x.__iadd__(1)`, and not just `x.__iadd__(1)` - the `i*` magic methods are still expected to return their result, even if that is `self` (importantly, per the documentation you linked, it *doesn't have to be* self). See also the disassembly of them in Lattyware's answer - both versions have a `STORE_FAST`. – lvc Oct 15 '12 at 23:48