What's the Difference Between Generator Expressions and List Comprehensions in Python?

Generator expressions (Python 2.4+) and list comprehensions (Python 2.0+) differ in the following ways:

Syntax

Syntactically, the difference between the two is that generator expressions are wrapped in parentheses and list comprehensions are wrapped in squared brackets:

# generator expression
(item for item in iterable)
# list comprehension
[item for item in iterable]

Consider, for example, the following where numbers are squared using generator expression:

squares = list(n ** 2 for n in range(5))
print(squares) # [0, 1, 4, 9, 16]

This is equivalent to the following:

def GenSquare(num):
    for n in range(num):
        yield(n ** 2)

squares = list(GenSquare(5))

print(squares) # [0, 1, 4, 9, 16]

The same example (of squaring numbers) can be written as list comprehension, for example, like so:

squares = [n ** 2 for n in range(5)]
print(squares) # [0, 1, 4, 9, 16]

This is equivalent to the following:

squares = list(map(lambda n: n ** 2, range(5)))
print(squares) # [0, 1, 4, 9, 16]

It can also be written in a loop, like so:

squares = []

for n in range(5):
    squares.append(n ** 2)

print(squares) # [0, 1, 4, 9, 16]

Return Type

Generator expressions return a generator object, while list comprehensions return a new list:

# generator syntax
squares = (n ** 2 for n in range(5))
print(squares) # <generator object <genexpr> at ...>
# list comprehension
squares = [n ** 2 for n in range(5)]
print(squares) # [0, 1, 4, 9, 16]

To return a list with generator syntax, you have to explicitly wrap the resulting generator object in a list, for example, like so:

# generator syntax
squares = list(n ** 2 for n in range(5))
print(squares) # [0, 1, 4, 9, 16]

Since generator expression return a generator object, it won't support list functions/operations (such as indexing, slicing, etc.) unless you explicitly convert it to a list.

Operation

Generator expressions are more memory efficient than list comprehensions. This is because list comprehension loads the entire list in memory, whereas a generator expression only loads one value in memory at a time. For example, you can check how much memory each of these use by using the sys.getsizeof() method:

from sys import getsizeof

ge = (n for n in range(5000))

ge_size = getsizeof(ge)
print(ge_size) # 112

lc = [n for n in range(5000)]

lc_size = getsizeof(lc)
print(lc_size) # 43032

This means that you can use generator expressions for very large, even infinite, sequences.


This post was published by Daniyal Hamid. Daniyal currently works as the Head of Engineering in Germany and has 20+ years of experience in software engineering, design and marketing. Please show your love and support by sharing this post.