Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python if else micro-optimization

In pondering optimization of code, I was wondering which was more expensive in python:

if x:
    d = 1
else:
    d = 2

or

d = 2
if x:
    d = 1

Any thoughts? I like the reduced line count in the second but wondered if reassignment was more costly than the condition switching.

like image 887
Gavin M. Roy Avatar asked Nov 27 '22 15:11

Gavin M. Roy


1 Answers

Don't ponder, don't wonder, measure -- with timeit at the shell command line (by far the best, simplest way to use it!). Python 2.5.4 on Mac OSX 10.5 on a laptop...:

$ python -mtimeit -s'x=0' 'if x: d=1' 'else: d=2'
10000000 loops, best of 3: 0.0748 usec per loop
$ python -mtimeit -s'x=1' 'if x: d=1' 'else: d=2'
10000000 loops, best of 3: 0.0685 usec per loop
$ python -mtimeit -s'x=0' 'd=2' 'if x: d=1'
10000000 loops, best of 3: 0.0734 usec per loop
$ python -mtimeit -s'x=1' 'd=2' 'if x: d=1'
10000000 loops, best of 3: 0.101 usec per loop

so you see: the "just-if" form can save 1.4 nanoseconds when x is false, but costs 40.2 nanoseconds when x is true, compared with the "if/else" form; so, in a micro-optimization context, you should use the former only if x is 30 times more likely to be false than true, or thereabouts. Also:

$ python -mtimeit -s'x=0' 'd=1 if x else 2'
10000000 loops, best of 3: 0.0736 usec per loop
$ python -mtimeit -s'x=1' 'd=1 if x else 2'
10000000 loops, best of 3: 0.076 usec per loop

...the ternary operator of the if/else has its own miniscule pluses and minuses.

When the differences are as tiny as this, you should measure repeatedly, establish what the noise level is, and ensure you're not taking differences "in the noise" as significant. For example, to compare statement vs expression if/else in the "x is true" case, repeat each a few times:

$ python -mtimeit -s'x=1' 'd=1 if x else 2'
10000000 loops, best of 3: 0.076 usec per loop
$ python -mtimeit -s'x=1' 'd=1 if x else 2'
10000000 loops, best of 3: 0.0749 usec per loop
$ python -mtimeit -s'x=1' 'd=1 if x else 2'
10000000 loops, best of 3: 0.0742 usec per loop
$ python -mtimeit -s'x=1' 'd=1 if x else 2'
10000000 loops, best of 3: 0.0749 usec per loop
$ python -mtimeit -s'x=1' 'd=1 if x else 2'
10000000 loops, best of 3: 0.0745 usec per loop

now you can state that the expression forms takes (on this machine and versions of key software) 74.2 to 76.0 nanoseconds -- the range is much more expressive than any single number would be. And similarly:

$ python -mtimeit -s'x=1' 'if x: d=1' 'else: d=2'
10000000 loops, best of 3: 0.0688 usec per loop
$ python -mtimeit -s'x=1' 'if x: d=1' 'else: d=2'
10000000 loops, best of 3: 0.0681 usec per loop
$ python -mtimeit -s'x=1' 'if x: d=1' 'else: d=2'
10000000 loops, best of 3: 0.0687 usec per loop
$ python -mtimeit -s'x=1' 'if x: d=1' 'else: d=2'
10000000 loops, best of 3: 0.0679 usec per loop
$ python -mtimeit -s'x=1' 'if x: d=1' 'else: d=2'
10000000 loops, best of 3: 0.0692 usec per loop

now you can state confidently that the statement form takes (under identical conditions) 67.9 to 69.2 nanoseconds; so its advantage, for x true, wrt the expression form, is 4.8 to 8.1 nanoseconds (it's quite fair to restrict this latter interval estimation to 6.3 to 6.8 nanoseconds, comparing min/min and max/max instead of min/max and max/min as the wider, more prudential estimate does).

How much time and energy is worth devoting to such microscopic differences, once you've realized for any given care that they are microscopic, is, of course, a different issue.

like image 94
Alex Martelli Avatar answered Nov 30 '22 05:11

Alex Martelli