from functools import wraps COUNTER = 0 def trace(fn): @wraps(fn) def wrapper(*a, **kw): global COUNTER COUNTER += 1 return fn(*a, **kw) return wrapper @trace def factorial(n: int) -> int: if n < 0: raise ValueError('negative') return 1 if n <= 1 else n * factorial(n - 1) def squares(limit): return [x * x for x in range(limit) if x % 2 == 0] def gen_pairs(seq): for i, v in enumerate(seq): yield (i, v) def make_adder(by=1): def add(x, *, scale=1): return (x + by) * scale return add def categorize(n): match n: case 0: return 'zero' case x if x < 0: return 'negative' case _: return 'positive' def run() -> None: print('factorials:', [factorial(i) for i in range(7)]) print('squares:', squares(10)) print('pairs:', list(gen_pairs('abcd'))) add5 = make_adder(5) print('adder:', add5(3, scale=2)) print('category:', [categorize(x) for x in (-1, 0, 7)]) if (n := sum(squares(8))) > 100: print('walrus-large:', n) else: print('walrus-small:', n) try: factorial(-1) except ValueError as e: print('caught:', str(e)) print('counter:', COUNTER) if __name__ == '__main__': run()