6

I'm not sure whether it's the same in Python.

Has anyone tried that before?

http://docs.python.org/library/operator#operator.iadd

Hanfei Sun
  • 45,281
  • 39
  • 129
  • 237

4 Answers4

19

There hardly is a difference in the work python performs for either statement:

>>> import dis
>>> def inplace_add():
...     a = 0
...     a += 1
... 
>>> def add_and_assign():
...     a = 0
...     a = a + 1
... 
>>> dis.dis(inplace_add)
  2           0 LOAD_CONST               1 (0)
              3 STORE_FAST               0 (a)

  3           6 LOAD_FAST                0 (a)
              9 LOAD_CONST               2 (1)
             12 INPLACE_ADD         
             13 STORE_FAST               0 (a)
             16 LOAD_CONST               0 (None)
             19 RETURN_VALUE        
>>> dis.dis(add_and_assign)
  2           0 LOAD_CONST               1 (0)
              3 STORE_FAST               0 (a)

  3           6 LOAD_FAST                0 (a)
              9 LOAD_CONST               2 (1)
             12 BINARY_ADD          
             13 STORE_FAST               0 (a)
             16 LOAD_CONST               0 (None)
             19 RETURN_VALUE        

The difference is a INPLACE_ADD versus a BINARY_ADD.

The resulting timings are too close to call which one would be faster:

>>> import timeit
>>> timeit.timeit('inplace_add', 'from __main__ import inplace_add', number=10000000)
0.32667088508605957
>>> timeit.timeit('add_and_assign', 'from __main__ import add_and_assign', number=10000000)
0.34172606468200684

So, in python, the difference is negligible. Don't worry about it.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • Great answer (I didn't know about the `dis` module, so thank you). One consideration is that the speed of execution may be affected by the other processes running at a given time. My approach was therefore to run both 1 million times in a function and compare the execution speed in `cProfile` many times (see below). I agree that the difference is negligible. – Aaron Newton Aug 13 '12 at 06:22
  • I don't really understand why using `a += 1` will call in-place operation when `a` is an immutable object, `integer`. AFAIK, integer is an immutable object in Python. The in-place operation should only make sense if an object is a mutable. Can someone explain to me? Thank you. – Lion Lai Jun 19 '23 at 09:11
  • 1
    @LionLai: The in-place operation is a _statement_, meaning it is part of the language, and works for *any* variable, whatever the type, provided that it supports the 'regular' operation (`+` here). The integer remains immutable, but the number of bytecode steps that the interpreter has to perform is fewer. It works because integers support the `+` addition operation. – Martijn Pieters Jun 19 '23 at 20:47
6

Nope

>>> bar = timeit.Timer("a += 1", "a = 0")
>>> bar.timeit(number=1000000)
0.064391136169433594
>>> bar = timeit.Timer("a = a + 1", "a = 0")
>>> bar.timeit(number=1000000)
0.064393997192382812
>>>
tMC
  • 18,105
  • 14
  • 62
  • 98
4

Yep, but the difference is marginal.

>>> timeit.Timer('x += 1', 'x = 0').timeit(10**8)
5.7387330532073975
>>> timeit.Timer('x = x + 1', 'x = 0').timeit(10**8)
6.04801607131958
>>> timeit.Timer('x += 1', 'x = 0').timeit(10**8)
5.790481090545654
>>> timeit.Timer('x = x + 1', 'x = 0').timeit(10**8)
6.083467960357666
Dietrich Epp
  • 205,541
  • 37
  • 345
  • 415
1

I took a slightly different approach using the cProfile module:

$ python -m cProfile test.py 
     4 function calls in 0.397 seconds

Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    0.397    0.397 test.py:2(<module>)
        1    0.205    0.205    0.205    0.205 test.py:2(add1)
        1    0.192    0.192    0.192    0.192 test.py:6(add2)
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}




aaron@zebrafish:~/pyad$ cat test.py 
def add1(a):
    for x in xrange(10 ** 6):
        a += 1

def add2(a):
    for x in xrange(10 ** 6):
        a = a + 1

add1(0)
add2(0)

After about 20 runs I would conclude that add2 (using a = a + 1) was very slightly faster, but not in all cases (perhaps try it with a greater number of loops). This is probably not the best heuristic, but I figure a greater number of repetitions with larger and larger numbers should indicate a performance difference.

EDIT - results for 10 ** 9 calls:

    1  216.119  216.119  216.119  216.119 test.py:2(add1)
    1  195.364  195.364  195.364  195.364 test.py:6(add2)
Aaron Newton
  • 2,124
  • 1
  • 28
  • 31