On 21May2019 18:11, CrazyVideoGamez <jasonanyil...@gmail.com> wrote:
I tried doing a list comprehension. I typed:
favorite_fruits = ['watermelon', 'blackberries']
print(fruit for fruit in favorite_fruits)
And I got:
<generator object <genexpr> at 0x0402C7B0>
What does this mean and what do I have to fix?
It means you didn't make a list comprehension. You've discovered a
similar thing though.
A list comprehension includes square brackets:
[ fruit for fruit in favorite_fruits ]
The result of that expression is literally a list, in this case
effectively a copy of your favorite_fruits list.
However, what you wrote was this:
fruit for fruit in favorite_fruits
and that is a generator expression. It is effectively an object that you
can iterate over, and it will yield the elements from favourite_fruits.
Importantly, it doesn't construct a list. It constructs a tiny function.
Why might we want such a thing? Because it is "lazy": it only computes
values which are actually asked for (consumed). The list comprehension
computes all the values, _and_ allocates a list and stores them! This
consumes more memory (except for small lists) and stalls your programme
while that work takes place.
It is equivalent to this function:
def elements_of(some_list):
for element in some_list:
yield element
That is a "generator function", and when you call it eg
"elements_of(favorite_fruits)" it doesn't run. Instead it returns you a
generator object which is effectively a call to the function frozen in
time.
The generator object is iterable, and when you iterate over it if fires
up the frozen function. The function runs until it hits a yield
statement, where it yields a value and that is the next value for the
iteration; the function freezes again then.
Consider this loop:
stop_at = 'watermelon'
for value in [ fruit for fruit in favorite_fruits ]:
print(value)
if value == stop_at:
break
This (a) constructs a list containing all the elements of
favorite_fruits then (b) iterates over the elements of that list. When
it hits a particular one of those elements it exits the loop.
If we unfold the "for" line a little:
elements = [ fruit for fruit in favorite_fruits ]
for value in elements:
The same amount of work is done, it just makes clear that the list
construction is a whole distinct step.
Now compare (generator expression in brackets, for clarity.:
stop_at = 'watermelon'
elements = fruit for fruit in favorite_fruits
for value in elements:
print(value)
if value == stop_at:
break
Now "elements" is not a list, it is a generator expression. You can
still iterate over this, and the printed output will be the same.
However, before the "for", _no_ elements of favorite_fruits have been
iterated over - almost no work has happened at all. Then as the for loop
iterates, it fetches values from "elements", which yields them as
needed.
So that when the loop stops early, no effort (or memory storage) is
wasted looking at the tail of the list.
Your list is very small, but for large lists this is a significant win.
Some lists are (notionally) infinitely large.
Cheers,
Cameron Simpson <c...@cskk.id.au>
--
https://mail.python.org/mailman/listinfo/python-list