A list comprehension uses square brackets and builds the whole list in memory. A generator expression uses round brackets and makes each value only when it is asked for.
The program
python
import sys squares_list = [x * x for x in range(1_000_000)] squares_gen = (x * x for x in range(1_000_000)) print(f"List: about {sys.getsizeof(squares_list) / 1_000_000:.0f} MB") print(f"Generator: {sys.getsizeof(squares_gen)} bytes") print(next(squares_gen)) print(next(squares_gen)) print(next(squares_gen))
example output · yours will differ
List: about 8 MB Generator: 200 bytes 0 1 4
How it works
- The list holds one million results.
sys.getsizeofmeasures only the list itself (its slots), and the number objects take more memory on top of that. - The generator holds no results. It remembers only where it is in the loop, so its size stays the same however long the range is.
next()asks the generator for its next value: 0, then 1, then 4.- The exact sizes depend on your Python version and your computer, so Run may show different numbers here. The gap between the two stays huge.
When to use each one
A generator can be used only once. After its values are used, it is empty:
python
gen = (x * x for x in range(5)) print(sum(gen)) print(sum(gen))
output
30 0
- Use a generator expression when you go through the values once, for example to add them up. You can pass it straight to a function, without the extra brackets:
sum(x * x for x in range(1_000_000)). - Use a list when you need to use the values more than once, find the length with
len(), or read items by index such assquares[10].