4

What's faster, a==2==b, or a==2 and b==2?

To be clear, expression one evaluates both of the items once, and does not compare a to b.

And this is worth a read: In Python, is an "and" statement or all() faster?

Community
  • 1
  • 1
noɥʇʎԀʎzɐɹƆ
  • 9,967
  • 2
  • 50
  • 67
  • 4
    Please take the time to [read this](http://ericlippert.com/2012/12/17/performance-rant/http://ericlippert.com/2012/12/17/performance-rant/) – Cory Kramer Jun 12 '15 at 16:06
  • @CoryKramer This is a self-answer question...? This is also kind of a "theoretical" question too. – noɥʇʎԀʎzɐɹƆ Jun 12 '15 at 16:15
  • 1
    I can see that, I'm just generally posting that comment. Questions like this often serve no use because they delve into unneccessary micro-optimizations [which are rarely the bottleneck in code](https://programmers.stackexchange.com/questions/99445/is-micro-optimisation-important-when-coding). Just write your code for readability and correctness, and worry about optimization **iff performance is an issue** and **iff this piece of the code** is causing the problem. – Cory Kramer Jun 12 '15 at 16:18
  • @JamesLu note that a self-answered question **should still meet the site guidelines**; this is very borderline on-topic. – jonrsharpe Jun 12 '15 at 16:21
  • @CoryKramer Gotcha. I find that blog post interesting. – noɥʇʎԀʎzɐɹƆ Jun 12 '15 at 16:21
  • @jonrsharpe Migrate to programmers.stackexchange.com? – noɥʇʎԀʎzɐɹƆ Jun 12 '15 at 16:22
  • 5
    @JamesLu This would be closed on Programmers. We would expect that you've already profiled your application to measure, if it really matters. – Thomas Owens Jun 12 '15 at 16:24
  • 2
    @JamesLu No, this question is on topic for Stack Overflow; it should not be migrated to Programmers. – durron597 Jun 12 '15 at 16:32

2 Answers2

5

Timing both methods with timeit.

I'm using len() to gauge the execution time better, as a way to delay immediate evaluation.

Setup string for both:

setup = """import random
import string
a = ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(2))
b = ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(2))"""

Final Test Expression A:

timeit.repeat("len(a)==2==len(b)", setup=setup, repeat=100)

Final Test Expression B:

timeit.repeat("len(a)==2 and len(b)==2", setup=setup, repeat=100)

Both of the tests run the expression one million times, records the time, then does that one hundred times.

Turns out, expression B is faster by about a tenth of a second. On my computer the average time is as follows:

  • A: 0.22025904178619385 seconds
  • B: 0.3740460252761841 seconds

Try it for yourself.

Random string generation thanks to this Stack Overflow question.

Community
  • 1
  • 1
noɥʇʎԀʎzɐɹƆ
  • 9,967
  • 2
  • 50
  • 67
  • 1
    This is somewhat unsurprising if you look at the bytecode using `dis` - expression A is 12 ops, vs. 8 for expression B – jonrsharpe Jun 12 '15 at 16:07
  • 1
    Could you expand on *"I'm using `len()` to gauge the execution time better"* - better than what? – jonrsharpe Jun 12 '15 at 16:09
  • @jonrsharpe Done, though I don't know how clear it is. – noɥʇʎԀʎzɐɹƆ Jun 12 '15 at 16:13
  • 1
    So you're just doing that to avoid hard-coding `2==2==2`? It seems like a lot of hoops to jump through, particularly the random strings when all you want is something `len(x) == 2`. It would be better to test these on a range of inputs - is there any difference in performance between the four cases (`a == 2 and b == 2`, `a == 2 and b != 2`, `a != 2 and b == 2`, `a != 2 and b != 2`), at least? – jonrsharpe Jun 12 '15 at 16:22
  • @jonrsharpe I really think this should be migrated after reading that. – noɥʇʎԀʎzɐɹƆ Jun 12 '15 at 16:24
3

According to the analysis of bytecode:

>>> dis.dis(compile('a==2==b', '', 'eval'))
  1           0 LOAD_NAME                0 (a)
              3 LOAD_CONST               0 (2)
              6 DUP_TOP
              7 ROT_THREE
              8 COMPARE_OP               2 (==)
             11 JUMP_IF_FALSE_OR_POP    21
             14 LOAD_NAME                1 (b)
             17 COMPARE_OP               2 (==)
             20 RETURN_VALUE
        >>   21 ROT_TWO
             22 POP_TOP
             23 RETURN_VALUE
>>> dis.dis(compile('a==2 and b==2', '', 'eval'))
  1           0 LOAD_NAME                0 (a)
              3 LOAD_CONST               0 (2)
              6 COMPARE_OP               2 (==)
              9 JUMP_IF_FALSE_OR_POP    21
             12 LOAD_NAME                1 (b)
             15 LOAD_CONST               0 (2)
             18 COMPARE_OP               2 (==)
        >>   21 RETURN_VALUE

Python need more operations to process a==2==b than a == 2 and b == 2

drgarcia1986
  • 343
  • 1
  • 5