Is any() evaluated lazily?

前端 未结 7 479
别跟我提以往
别跟我提以往 2021-01-18 03:59

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 an

相关标签:
7条回答
  • 2021-01-18 04:23

    JoshiRaez is the actual correct answer.

    Here is an example

    a = []
    
    any([True, a[0]])
    

    will fail

    On the other side, using OR (or AND) will not fail since its not a function:

    a = []
    True or a[0]
    
    0 讨论(0)
  • 2021-01-18 04:25

    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.

    0 讨论(0)
  • 2021-01-18 04:25

    No. All and Any support shortcircuiting but they don't make the conditionals interpretation lazy.

    If you want an All or Any using lazy evaluation you need to pass them a generator. Or else the values get evaluated in the moment the list/set/iterator/whatever is constructed

    0 讨论(0)
  • 2021-01-18 04:27

    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 == 100 for x in range(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.

    0 讨论(0)
  • 2021-01-18 04:28

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

    import random
    
    def some(x):
        print(x, end = ', ')
        return random.random() < 0.25
    
    for i in range(5):
        print(any(some(x) for x in range(10)))
    

    typical run:

    0, 1, 2, True
    0, 1, True
    0, True
    0, 1, 2, 3, True
    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, False
    
    0 讨论(0)
  • 2021-01-18 04:41

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

    def some(x, result=True):
        print(x)
        return result
    
    >>> print(any(some(x) for x in range(5)))
    0
    True
    
    >>> print(any(some(x, False) for x in range(5)))
    0
    1
    2
    3
    4
    False
    

    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.

    0 讨论(0)
提交回复
热议问题