Python builtin “all” with generators

后端 未结 5 839
太阳男子
太阳男子 2020-12-18 07:07

I have the following problem with python\'s \"all\" and generators:

G = (a for a in [0,1])
all(list(G))   # returns False - as I expected

B

相关标签:
5条回答
  • 2020-12-18 07:48

    Aha!

    Does Python(x,y) happen to import numpy? [It looks like it.]

    Python 2.7.2 (v2.7.2:8527427914a2, Jun 11 2011, 15:22:34) 
    [GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin
    Type "help", "copyright", "credits" or "license" for more information.
    >>> 
    >>> 
    >>> G = (a for a in [0,1])
    >>> all(G)
    False
    >>> from numpy import all
    >>> 
    >>> G = (a for a in [0,1])
    >>> all(G)
    True
    >>> 
    

    Here's an explanation by Robert Kern:

    It [all --ed] works on arrays and things it can turn into arrays by calling the C API equivalent of numpy.asarray(). There's a ton of magic and special cases in asarray() in order to interpret nested Python sequences as arrays. That magic works fairly well when we have sequences with known lengths; it fails utterly when given an arbitrary iterator of unknown length. So we punt. Unfortunately, what happens then is that asarray() sees an object that it can't interpret as a sequence to turn into a real array, so it makes a rank-0 array with the iterator object as the value. This evaluates to True.

    0 讨论(0)
  • 2020-12-18 07:57

    I found out in python 3.2.3 if the value 0 is in the list all() will return False.

    for all() to work you have to avoid having a zero in the iteration list.

    It leads me to believe that zero is used as an end for the iteration.

    Python 3.2.3 (default, Apr 11 2012, 07:15:24) [MSC v.1500 32 bit (Intel)] on win32

     print(all([]))          # prints True
     print(all([0]))         # prints False
    
     print(all([2, 3]))      # prints True
     print(all([2, 3, 0]))   # prints False
    
    0 讨论(0)
  • 2020-12-18 07:58
    >>> G = (a for a in [0,1])
    >>> all(list(G))
    False
    >>> G = (a for a in [0,1])
    >>> all(G)
    False
    

    No True. However:

    >>> G = (a for a in [0,1])
    >>> all(list(G))
    False
    >>> all(G)
    True
    >>> all([])
    True
    

    If you call all a second time on the generator, you'll get True, as there are no False items left in the generator. As you can see, any empty sequence will work the same.

    For this particular example, all short-circuits, so you have 1 left to be generated after it returns False because of the leading 0 (if you don't use list) -- so it will return True the second time despite not being empty.

    0 讨论(0)
  • 2020-12-18 08:05
    """
    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:# if element is zero returns False  
                return False
        return True
    """
    

    if you have '0' ( zeros in your iter) you will get False, when using all.

    iters with zeros

    l = [ x for x in range(10)]
    l1 = range(10)
    g = (x for  x in range(10))
    d = {k: v for k, v in zip(range(10), range(10)) }
    t = tuple(l)
    s = set(l)
    for i in [ l , l1, g , d , t , s]:
        print(type(i), i , "is iter " , all(i))
    

    Out put :

    <class 'list'> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] is iter  False
    <class 'range'> range(0, 10) is iter  False
    <class 'generator'> <generator object <genexpr> at 0x102a7d938> is iter  False
    <class 'dict'> {0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9} is iter  False
    <class 'tuple'> (0, 1, 2, 3, 4, 5, 6, 7, 8, 9) is iter  False
    <class 'set'> {0, 1, 2, 3, 4, 5, 6, 7, 8, 9} is iter  False
    

    iters without zeros

    l = [ x for x in range(1, 10)]
    l1 = range(1, 10)
    g = (x for  x in range(1, 10))
    d = {k: v for k, v in zip(range(1, 10), range(1, 10)) }
    t = tuple(l)
    s = set(l)
    for i in [ l , l1, g , d , t , s]:
        print(type(i), i , "is iter " , all(i))
    

    Out put :

    <class 'list'> [1, 2, 3, 4, 5, 6, 7, 8, 9] is iter  True
    <class 'range'> range(1, 10) is iter  True
    <class 'generator'> <generator object <genexpr> at 0x102a7d938> is iter  True
    <class 'dict'> {1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9} is 
    iter  True
    <class 'tuple'> (1, 2, 3, 4, 5, 6, 7, 8, 9) is iter  True
    <class 'set'> {1, 2, 3, 4, 5, 6, 7, 8, 9} is iter  True
    
    0 讨论(0)
  • 2020-12-18 08:11

    No, it doesn't. The following snippet returns False

    G = (a for a in [0,1])
    all(G)         # returns False
    

    Are you perhaps doing the following

    G = (a for a in [0,1])
    all(list(G))   # returns False
    all(G)         # returns True!
    

    In that case, you are exhausting the generator G when you construct the list, so the final call to all(G) is over an empty generator and hence returns the equivalent of all([]) -> True.

    A generator can't be used more than once.

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