5

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

But:

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

Can anybody explain that?

UPDATE: I swear I get this! Check this out:

In [1]: G = (a for a in [0,1])

In [2]: all(G)
Out[2]: True

I am using Python 2.6.6 with IPython 0.10.2, all installed within the Python(x,y) package. Strangely enough, I get "True" (above) when I use the Spider IDE, and "False" in pure console...

UPDATE 2: As DSM pointed out, it seems to be a numpy problem. Python(x,y) loads numpy, and all(G) was actually calling numpy.all(G) rather then the builtin all(). A quick workaround is to write:

__builtins__.all(G)

Thank you all for your help!

-maciej

DSM
  • 342,061
  • 65
  • 592
  • 494
maciej
  • 59
  • 3

5 Answers5

13

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.

DSM
  • 342,061
  • 65
  • 592
  • 494
  • It's ipython that's importing numpy. It can be set up to `from pylab import *` automatically. If you're using it only for simple scientific computing, this is pretty handy.. Except for the `all` bug (and a few others builtins that are clobbered, though the others behave pretty well). – drevicko Jun 15 '14 at 21:05
7

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.

agf
  • 171,228
  • 44
  • 289
  • 238
donkopotamus
  • 22,114
  • 2
  • 48
  • 60
  • Ah, beat me by a minute. The only thing I'd add is that the original all(G) doesn't exhaust the generator: G=(a for a in [0,1]); all(G); print list(G) gives [1], because the all short-circuits. – DSM Sep 20 '11 at 21:36
  • @DSM I disagree, The submitter is actually testing `all(list(G))`, and it is the `list(G)` that is exhausting the generator. – donkopotamus Sep 20 '11 at 21:40
  • I never said that the list(G) didn't exhaust the generator. I said that the original all(G) doesn't exhaust the generator, which it doesn't, and which might be surprising, so I thought worth mentioning. – DSM Sep 20 '11 at 21:47
  • Sorry for the downvote, but the OP's code doesn't appear to make the mistake you mention, and DSM's answer does explain things, so I'd prefer it to be at the top.. – drevicko Jun 15 '14 at 21:08
3
>>> 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.

agf
  • 171,228
  • 44
  • 289
  • 238
0

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
"""
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
Bangi
  • 113
  • 6