Python Forum

Full Version: What is the difference between a generator and a list comprehension?
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
I'm new to generators. Reuven Lerner describes them as "lazy lists"

This one assigns the letters of a string to alist a prescribed number of times.

But alist has no values.

Is this because the generator only makes the values when called by print(list(alist))??

What exactly is alist here? Is it like a function that can be called?

#! /usr/bin/python3
# simple generator

myString = 'generator'
n = len(myString)
max_times = 12
alist = (myString[x % n] for x in range(max_times))

# alist returns <generator object <genexpr> at 0x7fb489ca4ba0> in Idle
# print(alist) returns <generator object <genexpr> at 0x7fb489ca4ba0> in Idle

print(list(alist)) # returns ['g', 'e', 'n', 'e', 'r', 'a', 't', 'o', 'r', 'g', 'e', 'n']
If I use a list comprehension, I get a list:

alist2 = [myString[x%n] for x in range(max_times)]
Enter alist2 in Idle and I immediately get:

Quote:>>> alist2
['g', 'e', 'n', 'e', 'r', 'a', 't', 'o', 'r', 'g', 'e', 'n']
>>>

What is the difference between a generator and a list comprehension??

Maybe, the generator uses less memory, only works on demand??
I can understand asking the difference between a generator and an iterator. They are very similar and just use slightly different mechanics. A list comprehension is something completely different. Essentially it is a compressed syntax for loop that creates a list.

A list comprehension will always used an iterator or generator. I can't think of a way to make a list comprehension that doesn't. For example, "range" is a generator. You can use range in a list comprehension.
odds = [x for x in range(1, 11, 2)]
You can now use an iterator with the resulting list and get the same result as using the generator. Here a list comprehension, a built-in generator and a home-brew generator all do the same thing.
for x in odds:
    print(x)

for x in range(1, 11, 2):
    print(x)

def odd_generator(start, end):
    while start < end:
        yield start
        start += 2

for x in odd_generator(1, 11):
    print(x)
I guess the answer to your question is that a list comprehension makes a list and a generator iterates through a collection. They are completely different things. You can iterate over a list that was created by a list comprehension, but the iterator used to do so has much more in common with a generator than the list comprehension. If you have a generator and you want to get a list you need to use some sort of comprehension, either the [x for x in ..] type, the list(generator) type, or a for loop with list.append().
Thanks!

Reading up on the subject, I was led to the difference between yield and return:

Quote:Python3 yield keyword returns a generator to the caller and the execution of the code starts only when the generator is iterated.

Use yield instead of return when the data size is large

Can't really say I grasp this yet, but it's a start!