Reputation: 1323
I wish to use the Python all()
function to help me compute something, but this something could take substantially longer if the all()
does not evaluate as soon as it hits a False
. I'm thinking it probably is short-circuit evaluated, but I just wanted to make sure. Also, is there a way to tell in Python how the function gets evaluated?
Editor's note: Because any
and all
are functions, their arguments must be evaluated before they are called. That often creates the impression of no short-circuiting - but they do still short-circuit.
To make sure that the short-circuiting can be effective, pass a generator expression, or other lazily evaluated expression, rather than a sequence. See Lazy function evaluation in any() / all() for details. Similarly, to force evaluation up-front, build a list or tuple explicitly; see How to prevent short-circuit evaluation? .
Upvotes: 16
Views: 3770
Reputation: 144
Make sure you don't do as I did initially which was to try to use short-circuiting to test for the existence of a method before calling it:
>>> class MyClass(object):
... pass
...
>>> a = MyClass()
>>> all([hasattr(a, 'b'), a.b()])
Traceback (most recent call last):
File "<interactive input>", line 1, in <module>
AttributeError: 'MyClass' object has no attribute 'b'
but
>>> hasattr(a, 'b') and a.b() # doesn't evaluate a.b() as hasattr(a, 'b') is false
False
In the first code snippet, Python evaluates the list before passing it to all()
so it still throws the exception. This is basically the same as using list()
to force all()
not to use short-circuit evaluation as in morningstar's answer
Upvotes: 3
Reputation: 60014
Yes, it short-circuits:
>>> def test():
... yield True
... print('one')
... yield False
... print('two')
... yield True
... print('three')
...
>>> all(test())
one
False
From the docs:
Return
True
if all elements of the iterable are true (or if the iterable is empty). Equivalent to:def all(iterable): for element in iterable: if not element: return False return True
So when it return
s False, then the function immediately breaks.
Upvotes: 25
Reputation: 9152
In answer to your question of whether you can tell all
to be either short-circuit evaluated or not, it is short-circuit by default, but if you wanted it not to be, you could do this:
result = all(list(iterable))
Though that has the possibly undesirable property that the whole list will be loaded into memory. I can't think how you would avoid that other than using a different function than all. For example
result = reduce(lambda x,y: x and y, iterable)
result = min(iterable) # surprisingly similar to all; YMMV if iterable contains non-booleans
Upvotes: -1
Reputation: 236124
Yes, all
does use short-circuit evaluation. For example:
all(1.0/x < 0.5 for x in [4, 8, 1, 0])
=> False
The above stops when x
reaches 1
in the list, when the condition becomes false. If all
weren't short-circuiting, we'd get a division by zero when x
reached 0
.
Upvotes: 8