Frontend Labs
β‹―

22. πŸ”Ž Checkpoint: generators, classes, and types

# 1. [Ch 13] What does this print?
def gen():
    yield 1
    return 2
g = gen()
print(list(g), list(g))

# 2. [Ch 14] What is wrong with this decorator?
def log_calls(fn):
    def wrapper(*args):
        print("calling", fn.__name__)
        fn(*args)
    return wrapper

# 3. [Ch 15] Why does this raise?
from dataclasses import dataclass
try:
    @dataclass
    class Bag:
        items: list = []
except ValueError as e:
    print(e)

# 4. [Ch 16] Make `Money(5) + Money(7) == Money(12)` and `sum([Money(1), Money(2)])` work.
Answers
  1. [1] []. The return value becomes StopIteration.value, not an item; the generator is exhausted after one pass.
  2. It drops the return value (return fn(*args)), ignores **kwargs, and lacks @functools.wraps(fn).
  3. mutable default <class 'list'> for field items is not allowed: use default_factory. The dataclass protects you from Ch 2.6.
  4. A frozen dataclass with __add__, plus __radd__ that handles 0 (because sum starts from 0): def __radd__(self, other): return self if other == 0 else self + other.

Exercises:

  1. Write a generator tail(path, n) that yields the last n lines of a file using collections.deque(maxlen=n).
  2. Write a @rate_limit(calls=5, per=1.0) decorator using a token bucket (HTTPS Ch 9).
  3. Add full type hints to logstat.py from Ch 12 and make mypy --strict pass.
  4. Write Hypothesis tests for a parse_duration("1h30m") -> seconds function.

Generated from real-life-python-guide.md Β· 8 Oct 2026 16:36