Skip to main content
Functional programming is a style where you describe what you want rather than spelling out every step of how to get it. Python isn’t a purely functional language, but it borrows the best functional ideas — and knowing when to apply them makes your code shorter, more readable, and far easier to test.

Functional vs Imperative Style

The difference becomes clear with a simple example — doubling a list of numbers:
The functional version has no loop, no temporary state, and no mutation — just a transformation applied to data.

Pure Functions

A pure function always returns the same output for the same input and produces no side effects (no writes to disk, no network calls, no changes to global state). Pure functions are trivial to test and safe to cache.
Aim to write as many pure functions as possible. Push side effects (database writes, API calls, file I/O) to the edges of your program, keeping the core logic pure and testable.

map() — Transform Every Element

map(function, iterable) applies a function to every element of an iterable and returns a lazy iterator.

filter() — Keep Only Matching Elements

filter(function, iterable) returns a lazy iterator containing only elements for which the function returns True.

reduce() — Collapse a Collection to a Single Value

reduce(function, iterable) from functools applies a two-argument function cumulatively, reducing the sequence to a single result.
reduce() is powerful but can hurt readability when overused. For simple totals and products, Python’s built-in sum(), max(), and min() are clearer. Reserve reduce() for custom accumulation logic that has no built-in equivalent.

functools.partial — Partial Application

functools.partial lets you pre-fill some arguments of a function, creating a new specialised version of it.

Chaining Operations

You can chain map, filter, and other functional tools into a readable pipeline. For Python, combining comprehensions with sum/max/min is often the most readable approach.

When to Use Functional Style vs Comprehensions

  • You already have a named function (avoids creating a redundant lambda): list(map(str.upper, words))
  • You are composing a pipeline with partial or passing operations as arguments
  • You want lazy evaluation and will not materialise the full list
  • You are writing a one-off transformation inline — comprehensions are more readable to most Python developers
  • You need both filtering and transformation in one step
  • The result needs to be a list, dict, or set specifically

Immutability in Practice

Functional programming favours immutable data — data that is never modified in-place. Python gives you several tools for this:
You don’t have to go fully immutable. A practical rule: treat function arguments as read-only, return new values rather than mutating inputs, and limit mutation to clearly defined “update” operations.