Remember your in operator

After you have worked with Python for a while you develop a sense that tingles when you are doing something that feels stupid, or wrong, on unaesthetic. I have found that more often than not someone before me apparently felt the same, and there is a more elegant, or Pythonic way of doing it. One of the simplest cases I find is with the in operator. Consider the following code:

if a == 1 or a == 7 or a == 15:
    do_some_cool_stuff()

This might be a personal pet peeve of mine, but that just feels tedious and somewhat prone to errors. Luckily there is a neater way of doing it using the in operator:

if a in (1, 7, 15):
    do_some_cool_stuff()

There, much less typing, and it looks nice, too!

Performance wise there isn’t that big a difference, at least on 32-bit Linux with CPython. Here are some comparisons with the help of ipython and timeit:

In [1]: a=16
 
In [2]: timeit a == 1 or a == 7 or a == 15
10000000 loops, best of 3: 167 ns per loop
 
In [3]: timeit a in (1, 7, 15)
10000000 loops, best of 3: 155 ns per loop
 
In [4]: timeit a in [1, 7, 15]
10000000 loops, best of 3: 157 ns per loop
 
In [5]: a=1
 
In [6]: timeit a == 1 or a == 7 or a == 15
10000000 loops, best of 3: 72.4 ns per loop
 
In [7]: timeit a in (1, 7, 15)
10000000 loops, best of 3: 83.4 ns per loop
 
In [9]: timeit a in [1, 7, 15]
10000000 loops, best of 3: 83.5 ns per loop

Similar Posts:

    None Found

10 Comments

  1. tasc:

    notice that in the second set of comparisons, if you change a = 1 to a = 15 you will see a slightly different picture

  2. Armin Ronacher:

    If the contents of the tuple are constant values, use a tuple instead of a list. Then the whole tuple is stored in the code instead of the opcodes to create it / the list.

  3. tasc:

    @Armin: in this particular case set would be more appropriate.

  4. ssadler:

    @tasc, why is that? Are sets more efficient for this operation?

  5. tasc:

    sets are hashes, in is a O(1) operation

  6. tdrusk:

    Cool. I am just getting used to Python. I am starting to get that tingly feeling you described.

    It took me a minute to figure out what you were doing with the list, but after reading a comment or two I realized that I had to do this for one number.
    x=10
    if x in (10,):
    print ‘hello’

    I suppose there’s more than one way to skin a cat.

  7. ssadler:

    @tdrusk: I don’t think it really improves readability to do it for one number.

  8. Ernie:

    Using set is faster than using 3 comparisons. So using in looks best and is fastest.

    In [1]: a=16

    In [2]: s=set([1,7,15])

    In [3]: timeit a==1 or a==7 or a==16
    10000000 loops, best of 3: 126 ns per loop

    In [4]: timeit a in s
    10000000 loops, best of 3: 107 ns per loop

  9. lorg:

    @Ernie:
    Note that your comparison isn’t really fair, as you don’t take into account the time spent building the set.
    Since usually you won’t reuse the set for other comparisons, and the idiom is “a in set([…])”, you should take it into account. See:
    In [2]: a = 16
    In [3]: timeit a==1 or a==7 or a==16
    10000000 loops, best of 3: 144 ns per loop
    In [4]: timeit a in set([1,7,15])
    1000000 loops, best of 3: 786 ns per loop

  10. Ernie:

    @lorg

    if you know enough about the logic of your program to hardcode a==1 or a==7 or a==15, then you know enough to hardcode set([1,7,15]) outside the loop.

    Creating the set takes ~6 times longer than doing one hardcoded comparison, but further comparisons are quite a bit faster. I think the choice of what to use depends on how many times you’ll execute the statement. But there should never be a case you create the set repeatedly.