Skip to content

Functional Programming Patterns

Beginning of the lesson

Functional Programming Patterns

Pure functions, immutability, and composable pipelines with functools and itertools

Big Idea: Functional programming (FP) is a style, not a separate language. You build programs from pure functions that map inputs to outputs without hidden side effects, treat data as immutable, and compose small functions into pipelines. Python is not a purely functional language, but it ships a strong FP toolbox: first-class functions, functools, itertools, comprehensions and generators. Used deliberately, these produce code that is easier to test, cache and reason about — used blindly, they produce unreadable one-liners. This topic is about applying FP where it pays off.
By the end you will be able to:
  • define a pure function and explain referential transparency,
  • choose immutable structures (tuple, frozenset, frozen dataclass) and avoid shared-mutable-state bugs,
  • reach for the right functools tool: reduce, partial, lru_cache, singledispatch,
  • stream data lazily with itertools (chain, islice, groupby, accumulate, takewhile),
  • compose small transformations into a readable pipeline,
  • state honestly when FP hurts readability in Python.

1. Pure functions and referential transparency

A function is pure when it satisfies two rules: (1) its return value depends only on its arguments, and (2) it causes no observable side effects — no mutating of external state, no I/O, no clock or random reads. The same inputs always yield the same output.

# PURE: output depends only on inputs, nothing external changes
def add_tax(price: float, rate: float) -> float:
    return round(price * (1 + rate), 2)

# IMPURE: reads a global, mutates a global, and does I/O
TOTAL = 0.0
def add_tax_bad(price: float) -> float:
    global TOTAL
    result = price * 1.2
    TOTAL += result          # side effect: mutates external state
    print(result)            # side effect: I/O
    return result

Referential transparency means any call to a pure function can be replaced by its result without changing the program. add_tax(100, 0.2) is interchangeable with 120.0 everywhere. That property is what makes pure functions trivially testable (no fixtures, no mocks), safe to cache, and safe to run in parallel — there is no shared state to corrupt.

Purity is a spectrum. A real program must eventually do I/O. The practical goal is a pure core (calculations) with a thin impure shell (reading files, printing, database writes) at the edges — often called functional core, imperative shell.

Continue this lesson on YourAIZone

The full lesson has the complete explanation, worked examples, common mistakes, tests with instant checking and an AI tutor. Start right away as a guest, or create an account to keep your progress.

In the full lesson

  • The complete explanation
  • Worked examples
  • Common mistakes and how to avoid them
  • Test questions: 15
  • AI tutor that answers questions about the topic
  • Progress tracking for students, parents and teachers