Python ยท easy

What are Python generators and when would you use them?

Asked in Data Engineer interviews, in the Python round.

Short answer

Lazy iterators built with yield, used for large or streamed data to save memory.

How to answer it

Definition

A generator is a function that produces values one at a time using yield instead of building and returning a whole collection. Calling it returns an iterator; nothing runs until you iterate, and only one value exists in memory at a time.

Syntax

def squares(n):
    for i in range(n):
        yield i * i             # yield, not return

gen = (x * x for x in range(n))  # generator expression, same idea

Example

def read_large_file(path):
    with open(path) as f:
        for line in f:          # the file object is itself lazy
            yield line.rstrip()

total = 0
for line in read_large_file("50gb.csv"):
    total += len(line)

Output

>>> g = squares(5)
>>> g
<generator object squares at 0x0000021F...>
>>> list(g)
[0, 1, 4, 9, 16]
>>> list(g)
[]                      # exhausted: a generator runs once

Memory

[x * x for x in range(10_000_000)]     # ~400 MB, built immediately
(x * x for x in range(10_000_000))     #  ~200 bytes, built lazily

The list holds every value at once. The generator holds one value and the state needed to compute the next.

Key points

FAQ

The 30-second answer

A generator is a function that uses yield instead of return, so it hands back one value at a time and keeps its state between them. Calling it does not run the body; iterating it does.
I use them whenever the data is larger than memory or arrives as a stream: reading a huge file line by line, or chaining processing stages so nothing is ever fully materialised. The memory profile stays flat no matter how many items pass through.
The trade-offs I would mention are that a generator is single use, so iterating twice gives nothing the second time, and that there is no length and no indexing. If I need either of those, I wanted a list.

In the interview

Practice this for real