DEV Community

Cover image for 🍲 Part 3: Advanced Iteration Tricks
Anik Sikder
Anik Sikder

Posted on

🍲 Part 3: Advanced Iteration Tricks

Chefs, Sous-chefs, and Lazy Pipelines

By now you’ve met:

  • The buffet (iterable: the source of food 🍱)
  • The waiter (iterator: walks forward πŸšΆβ€β™‚οΈ)
  • The autopilot waiter (generator: powered by yield πŸ€–)

But real restaurants need teams sous-chefs, assistants, conveyor belts, and clever tricks to keep food moving.

Today we explore advanced iteration: itertools, yield from, generator delegation, cloning with tee, and lazy pipelines.
And this time, we’ll tie it to real-world mini-projects so you see the practical magic.


🍴 1. itertools β†’ Kitchen Gadgets

Think of itertools as Python’s drawer of restaurant gadgets simple tools that make iteration effortless.

Fun Example: Endless Breadsticks

import itertools

for bread in itertools.count(1):  # waiter counts forever
    if bread > 5:
        break
    print(bread)
Enter fullscreen mode Exit fullscreen mode

🍞 Output:

1
2
3
4
5
Enter fullscreen mode Exit fullscreen mode

Behind the curtain:

  • count is just a tiny iterator with a counter.
  • Each next() increments, no giant list needed.

🍟 Real-World Mini-Project: Streaming Logs

import itertools

def read_logs(filename):
    with open(filename) as f:
        for line in f:
            yield line.strip()

# Look only at the first 5 errors lazily
logs = read_logs("server.log")
errors = (l for l in logs if "ERROR" in l)
for e in itertools.islice(errors, 5):
    print("🚨", e)
Enter fullscreen mode Exit fullscreen mode

πŸ‘‰ You can process gigantic logs without loading them all into memory.


πŸ₯‘ 2. yield from β†’ Waiter Delegation

When a waiter has too many trays, he calls an assistant:
β€œHey intern, serve these dishes for me.”

Example:

def menu():
    yield 1
    yield 2
    yield from [3, 4]  # delegation
Enter fullscreen mode Exit fullscreen mode

Output β†’ [1, 2, 3, 4].

Behind the curtain:

  • yield from iterable expands into a for loop.
  • It even forwards exceptions and return values.

πŸ• Real-World Mini-Project: Nested Config Loader

def load_base():
    yield "db=sqlite"
    yield "timeout=30"

def load_dev():
    yield from load_base()
    yield "debug=true"

print(list(load_dev()))
# ['db=sqlite', 'timeout=30', 'debug=true']
Enter fullscreen mode Exit fullscreen mode

πŸ‘‰ yield from = clean delegation of tasks (like dev configs building on base configs).


🍝 3. Generator Delegation (Sous-Chefs)

Restaurants don’t have one chef for all courses. They delegate: appetizers, mains, desserts.

def appetizer():
    yield "salad πŸ₯—"
    yield "soup 🍜"

def main_course():
    yield "steak πŸ₯©"
    yield "pasta 🍝"

def dessert():
    yield "cake 🍰"

def full_meal():
    yield from appetizer()
    yield from main_course()
    yield from dessert()

print(list(full_meal()))
Enter fullscreen mode Exit fullscreen mode

Output β†’ ['salad πŸ₯—','soup 🍜','steak πŸ₯©','pasta 🍝','cake 🍰'].

🍜 Real-World Mini-Project: File Processing Pipeline

def read_lines(path):
    with open(path) as f:
        for line in f:
            yield line

def parse_csv(lines):
    for line in lines:
        yield line.strip().split(",")

def filter_users(rows):
    for row in rows:
        if int(row[2]) > 30:  # age > 30
            yield row

def users_over_30(path):
    yield from filter_users(parse_csv(read_lines(path)))

for u in users_over_30("users.csv"):
    print(u)
Enter fullscreen mode Exit fullscreen mode

πŸ‘‰ This is a real pipeline: one generator hands off to the next like sous-chefs in a line.


πŸ₯‚ 4. itertools.tee β†’ Cloning Waiters

Normally: one waiter, one trip. If Alice eats, Bob gets an empty plate.

tee = photocopy the waiter so both can eat.

import itertools

it = iter([1, 2, 3])
alice, bob = itertools.tee(it)

print(list(alice))  # [1, 2, 3]
print(list(bob))    # [1, 2, 3]
Enter fullscreen mode Exit fullscreen mode

Behind the curtain:

  • tee buffers values if one consumer lags behind.
  • Watch out: memory grows if consumers are very out of sync.

🍀 Real-World Mini-Project: Dual Consumers (Analytics + Logging)

orders = (f"Order {i}" for i in range(1, 6))

# Clone the stream
chef, cashier = itertools.tee(orders)

print("Chef prepares:", list(chef))
print("Cashier logs:", list(cashier))
Enter fullscreen mode Exit fullscreen mode

πŸ‘‰ Same data stream, used by two different subsystems.


🍧 5. Lazy Pipelines β†’ Conveyor Belts of Food

Now the coolest trick: combine everything into a conveyor belt where dishes flow step by step.

import itertools

nums = range(1, 1000000)

pipeline = itertools.islice(
    (n**2 for n in nums if n % 2),  # odd squares
    5
)

print(list(pipeline))  # [1, 9, 25, 49, 81]
Enter fullscreen mode Exit fullscreen mode

Behind the curtain:

  • Each stage is lazy β†’ nothing happens until next() is called.
  • You can chain infinite data sources safely.

🍜 Real-World Mini-Project: Live Order Filter

import itertools

def infinite_orders():
    n = 1
    while True:
        yield f"Pizza #{n}"
        n += 1

orders = itertools.islice(
    (o for o in infinite_orders() if "3" not in o),  # skip unlucky 3s
    5
)

print(list(orders))
Enter fullscreen mode Exit fullscreen mode

Output:

['Pizza #1', 'Pizza #2', 'Pizza #4', 'Pizza #5', 'Pizza #6']
Enter fullscreen mode Exit fullscreen mode

πŸ‘‰ Streaming infinite orders, but filtered + capped safely.


🎨 ASCII Mental Model

[ Buffet ] β†’ [ Waiter ] β†’ [ Gadget ] β†’ [ Filter ] β†’ [ Map ] β†’ [ Eater ]
Enter fullscreen mode Exit fullscreen mode

Think of it as a restaurant conveyor belt each chef only touches one dish at a time, dishes move lazily, no giant tray dumped all at once.


🎬 Wrap-Up

Today we upgraded from one waiter to a whole restaurant team:

  • itertools: kitchen gadgets (count, cycle, chain, islice).
  • yield from: waiter delegation.
  • generator delegation: sous-chefs working in harmony.
  • tee: cloning waiters with buffering.
  • lazy pipelines: conveyor belts of infinite food.

πŸ‘‰ Next up (Part 4): Coroutines waiters who don’t just serve, but can also take your orders mid-service (send, throw, async/await).

Top comments (0)