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

Reply via email to