Jace Browning
Jace Browning

Reputation: 12672

Why doesn't all() stop on the first False element?

From the docs, all is equivalent to:

def all(iterable):
    for element in iterable:
        if not element:
            return False
    return True

Then why do I get this output:

# expecting: False

$ python -c "print( all( (isinstance('foo', int), int('foo')) ) )"
Traceback (most recent call last):
  File "<string>", line 1, in <module>
ValueError: invalid literal for int() with base 10: 'foo'

When:

# expecting: False

$ python -c "print( isinstance('foo', int) )"
False

Upvotes: 4

Views: 1096

Answers (4)

user4815162342
user4815162342

Reputation: 155296

Your intuition regarding all is correct; you only need to work a little harder to set up a lazy sequence. For example:

def lazy():
    yield isinstance("foo", int)   # False
    yield int("foo")               # raises an error, but we won't get here

>>> all(lazy())
False
>>> list(lazy())
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in lazy
ValueError: invalid literal for int() with base 10: 'foo'

Upvotes: 2

Jace Browning
Jace Browning

Reputation: 12672

If the desire to stop evaluation after the first False condition is specifically to perform type checking, something like this will work better:

if not isinstance(other, MyClass):
    return False
else:
    return all((self.attr1 == other.attr2,
                self.attr2 == other.attr2)) # etc.

Simplified version from @catchmeifyoutry:

return isinstance(other, MyClass) and all((self.attr1 == other.attr2,
                                           self.attr2 == other.attr2)) # etc.

Upvotes: 1

Daniel Roseman
Daniel Roseman

Reputation: 599866

One (fairly ugly) way to get the behaviour you want is via lambdas:

all(f() for f in (lambda: isinstance('foo', int), lambda: int('foo')))

Upvotes: 7

Karoly Horvath
Karoly Horvath

Reputation: 96286

Arguments are evaluated before calling a function. In this case first you have to create the tuple you pass to all.

all never had a chance to check them, the exception was thrown before that.

>>> int('foo')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: invalid literal for int() with base 10: 'foo'

Upvotes: 5

Related Questions