Topic 12 / 15

Comprehensions, Iterators & Generators

~10 min read  //  Python Series  //  Coding India

List Comprehensions

Build a list from an iterable in one expression — Python’s signature move:

nums = [1, 2, 3, 4, 5, 6]

squares = [n ** 2 for n in nums]
# [1, 4, 9, 16, 25, 36]

evens = [n for n in nums if n % 2 == 0]      # with a filter
# [2, 4, 6]

labels = [f"#{n}" for n in nums if n > 3]
# ['#4', '#5', '#6']

Read it as: “collect f(n) for each n in nums if condition”. One filter and one transform is the sweet spot — beyond that, use a regular loop for readability.

Dict & Set Comprehensions

users = ["Ravi", "Asha", "Dev"]

lengths = {name: len(name) for name in users}
# {'Ravi': 4, 'Asha': 4, 'Dev': 3}

initials = {name[0] for name in users}        # a set
# {'R', 'A', 'D'}

# invert a dict
by_id = {1: "ravi", 2: "asha"}
by_name = {v: k for k, v in by_id.items()}

The Iterator Protocol

A for loop calls iter() on your object, then next() repeatedly until StopIteration. Anything implementing that is iterable — lists, strings, files, dict views, generators. That’s why one loop syntax works everywhere.

Generators — Lazy Sequences

A function with yield returns a generator: it produces values one at a time, on demand, remembering where it left off. Nothing is computed until you ask:

def countdown(n):
    while n > 0:
        yield n
        n -= 1

for x in countdown(3):
    print(x)         # 3, 2, 1

The killer use case is large data — process a 10 GB log file with constant memory:

def error_lines(path):
    with open(path, encoding="utf-8") as f:
        for line in f:                    # files are already lazy
            if "ERROR" in line:
                yield line.rstrip()

for line in error_lines("app.log"):
    print(line)                           # never loads the whole file

Generator Expressions

A comprehension with parentheses — lazy instead of building a list:

total = sum(n ** 2 for n in range(1_000_000))   # no million-item list created
has_admin = any(u.is_admin for u in users)       # stops at the first True

Pipelines

Generators compose into streaming pipelines — each stage pulls from the previous one, one item at a time:

lines  = (l.strip() for l in open("data.csv", encoding="utf-8"))
rows   = (l.split(",") for l in lines if l)
scores = (int(r[1]) for r in rows)
print(max(scores))