Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passing generator expressions to any() and all()

I was just messing around in the Python interpreter and I came across some unexpected behavior.

>>> bools = (True, True, True, False)
>>> all(bools)
False
>>> any(bools)
True

Ok, so far nothing out of the ordinary...

>>> bools = (b for b in (True, True, True, False))
>>> all(bools)
False
>>> any(bools)
False

Here's where things start getting spooky. I figure this happens because the all function iterates over the generator expression, calling its __next__ method and using up the values until it encounters one that is False. Here's some evidence to back that theory up:

>>> bools = (b for b in (True, False, True, True))
>>> all(bools)
False
>>> any(bools)
True

I think the result is different because the False is not at the end, so there are still some unused values left in the generator. If you type

>>> bools = (b for b in (True, False, True, True))
>>> all(bools)
False
>>> list(bools)
[True, True]

It seems like there are only 2 remaining values.

So, why exactly does this really happen? I'm sure there are many details that I'm missing.

like image 460
sam-pyt Avatar asked Jul 15 '19 18:07

sam-pyt


People also ask

Can a generator function have multiple yield expressions?

If you want to return multiple values from a function, you can use generator functions with yield keywords. The yield expressions return multiple values. They return one value, then wait, save the local state, and resume again.

What is generator expression in Python?

Python generators are a simple way of creating iterators. All the work we mentioned above are automatically handled by generators in Python. Simply speaking, a generator is a function that returns an object (iterator) which we can iterate over (one value at a time).

Can we call generator multiple times in Python?

If you want to reuse this generator multiple times, you can use functools. partial. This will wrap the generator function in another function so each time you call func_with_yield() it creates the same generator function. Note: It also accepts function arguments for FunctionWithYield(args) if you have arguments.

Is generator faster than list?

List comprehensions are usually faster than generator expressions as generator expressions create another layer of overhead to store references for the iterator. However, the performance difference is often quite small.


1 Answers

The problem that you are having is that you are using the generator after it has produced all the values.

You can verify this by running the following code:

>>> bools = (b for b in (True, False, True, True))
>>> all(bools) # once the False is found it will stop producing values
True
>>> next(bools) # next value after False which is True
True
>>> next(bools) # next value after True which is True
True
>>> next(bools)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

This will work:

>>> bools = (b for b in (True, False, True, True))
>>> all(bools)
False
>>> bools = (b for b in (True, False, True, True))
>>> any(bools)
True
like image 137
lmiguelvargasf Avatar answered Sep 30 '22 17:09

lmiguelvargasf