Skip to content Skip to sidebar Skip to footer

Is Any() Evaluated Lazily?

I am writing a script in which i have to test numbers against a number of conditions. If any of the conditions are met i want to return True and i want to do that the fastest way p

Solution 1:

Yes, any() and all() short-circuit, aborting as soon as the outcome is clear: See the docs:

all(iterable)

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:
            returnFalsereturnTrue

any(iterable)

Return True if any element of the iterable is true. If the iterable is empty, return False. Equivalent to:

def any(iterable):
    for element in iterable:
        if element:
            returnTruereturnFalse

Solution 2:

While the all() and any() functions short-circuit on the first "true" element of an iterable, the iterable itself may be constructed in a non-lazy way. Consider this example:

>> any(x == 100for x inrange(10**8))
True

This will take several seconds to execute in Python 2 as range(10**8) constructs a list of 10**8 elements. The same expression runs instantly in Python 3, where range() is lazy.

Solution 3:

As Tim correctly mentioned, any and all do short-circuit, but in your code, what makes it lazy is the use of generators. For example, the following code would not be lazy:

print(any([slow_operation(x) for x in big_list]))

The list would be fully constructed and calculated, and only then passed as an argument to any.

Generators, on the other hand, are iterables that calculate each item on demand. They can be expressions, functions, or sometimes manually implemented as lazy iterators.

Solution 4:

Yes, it's lazy as demonstrated by the following:

defsome(x, result=True):
    print(x)
    return result

>>> print(any(some(x) for x inrange(5)))
0True>>> print(any(some(x, False) for x inrange(5)))
01234False

In the first run any() halted after testing the first item, i.e. it short circuited the evaluation.

In the second run any() continued testing until the sequence was exhausted.

Solution 5:

Yes, and here is an experiment that shows it even more definitively than your timing experiment:

import random

defsome(x):
    print(x, end = ', ')
    return random.random() < 0.25for i inrange(5):
    print(any(some(x) for x inrange(10)))

typical run:

0, 1, 2, True0, 1, True0, True0, 1, 2, 3, True0, 1, 2, 3, 4, 5, 6, 7, 8, 9, False

Post a Comment for "Is Any() Evaluated Lazily?"