2

When testing if multiple conditions are True, are and statements or all() faster? For example:

if '1234'.isdigit() and '4567'.isdigit() and '7890'.isdigit(): 
    print "All are digits!"

or

if all(['1234'.isdigit(), '4567'.isdigit(), '7890'.isdigit()]): 
    print "All are digits!"

Thanks!

Joe Flip
  • 1,076
  • 4
  • 21
  • 37
  • I would propose that if nothing else, `all` looks better... why don't you set up a big loop and see what the results are? – aardvarkk Feb 28 '13 at 21:19
  • 3
    More importantly, I'm willing to bet no real program you can possibly devise or even imagine will ever need to care about the speed of such a thing with only 3 values. – abarnert Feb 28 '13 at 21:21

3 Answers3

11

ands are faster, there is no list creation and no function call.

In [10]: %timeit '1234'.isdigit() and '4567'.isdigit() and '7890'.isdigit()
1000000 loops, best of 3: 186 ns per loop

In [11]: %timeit all(['1234'.isdigit(), '4567'.isdigit(), '7890'.isdigit()])
1000000 loops, best of 3: 323 ns per loop

 

ands wouldn't even unnecessarily evaluate things:

In [1]: def x():
   ...:     print 'call'
   ...:     return False
   ...:

In [2]: x() and x()
call
Out[2]: False

In [3]: all([x(), x()])
call
call
Out[3]: False
Pavel Anossov
  • 60,842
  • 14
  • 151
  • 124
  • What's that percentage sign syntax? – Colonel Panic Feb 28 '13 at 21:19
  • Minor point: it tends to be faster to make a tuple than a list. Seldom worth worrying about in real code but it can sometimes account for 20-25% of the time in tiny benchmarks like this. – DSM Feb 28 '13 at 21:26
  • 1
    @DSM -- This is definitely true in places where the tuples can be interned -- e.g. if they contain only literals. I'm not sure how they compare in other cases. – mgilson Feb 28 '13 at 21:41
  • @mgilson: well, now you've made me check. :^) I find that using `all(('1234'.isdigit(), '4567'.isdigit(), '7890'.isdigit()))` is 20% faster than the same with a list, even though the components aren't literals. – DSM Feb 28 '13 at 21:44
  • @mgilson: If you need to optimize code that already takes under 500ns, it's pretty much worth trying everything just to see… – abarnert Feb 28 '13 at 21:44
  • @DSM -- Cool. Thanks for checking. I only commented because I *know* that the case where it can be interned is faster (just from looking at the bytecode). Did you by chance look at the bytecode from that one? – mgilson Feb 28 '13 at 21:49
  • @mgilson: the two differ only in `BUILD_TUPLE` vs `BUILD_LIST`. – DSM Feb 28 '13 at 22:00
  • @DSM -- Yep. I checked it out myself too. Neat. – mgilson Feb 28 '13 at 22:02
5

The second one evaluates all of the conditions, puts those boolean values into a list and then checks to see if they're all true.

The first, on the other hand, just checks them all one-by-one and stops at the first false condition (if there is one). The first one is definitely faster, as Pavel's answer shows.

You could also use a generator, which lets all short-circuit:

all(str.isdigit(s) for s in your_strings)
Blender
  • 289,723
  • 53
  • 439
  • 496
2

If you really want the fastest way to deal with 3 static values, and the dozens of nanoseconds of difference actually matters in your code:

if True:
    print "All are digits!"

Or, even faster:

print "All are digits!"

In any case where the performance matters in the slightest, you will have a large and/or dynamic set of values, and you simply can't do that with and, except by creating an explicit for loop:

value = True
for s in strings:
    value = value and s.isdigit()
    if not value:
        break
if value:
    print "All are digits!"

And you can immediately see how the and isn't helping things at all:

for s in strings:
    if not s.isdigit():
        break
else:
    print "All are digits!"

But if you want to do things faster with all, you can use a generator expression (or a map/imap call) instead of a list comprehension, and it's just as fast, and readable, with a large, dynamic sequence as with a small, static one:

if all((x.isdigit() for x in ('1234', '4567', '7890')):
    print "All are digits!"

if all((x.isdigit() for x in strings):
    print "All are digits!"

If the sequence is very big, and it's possible that some of the values are false, this will be hugely faster than anything involving building a list of all of the True/False values.

abarnert
  • 354,177
  • 51
  • 601
  • 671