Functional Programming Patterns in Python

· 4 min read · Updated March 12, 2026 · intermediate
python functional-programming patterns

Functional programming in Python is not about writing mathematically pure code—it is about writing code that is easier to reason about. The patterns here help you write smaller, more composable functions that do one thing well.

This guide covers the core functional programming patterns you will use daily in Python codebases.

Higher-Order Functions

A higher-order function either takes a function as an argument or returns a function. Python built-in functions like sorted() use this pattern:

words = ["banana", "apple", "cherry"]

# sorted() takes a key function as argument
sorted(words, key=len)  # [apple, banana, cherry]

You can also return functions from functions:

def multiplier(factor):
    def multiply(x):
        return x * factor
    return multiply

double = multiplier(2)
double(5)  # 10

This is useful for creating specialized functions from generic ones.

map(), filter(), and reduce()

These three functions form the backbone of functional data transformation in Python.

map() - Transform Each Element

map() applies a function to every element in an iterable:

numbers = [1, 2, 3, 4, 5]

# Square each number
squared = list(map(lambda x: x ** 2, numbers))
# [1, 4, 9, 16, 25]

filter() - Keep What Matches

filter() keeps only elements that satisfy a condition:

numbers = [1, 2, 3, 4, 5, 6]

# Keep only even numbers
evens = list(filter(lambda x: x % 2 == 0, numbers))
# [2, 4, 6]

reduce() - Combine Elements

reduce() from functools combines elements into a single value:

from functools import reduce

numbers = [1, 2, 3, 4]

product = reduce(lambda x, y: x * y, numbers)
# 24

Combining These Functions

The real power comes from chaining these functions together:

from functools import reduce

data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

# Square the even numbers, then sum them
result = reduce(
    lambda x, y: x + y,
    map(lambda x: x ** 2, filter(lambda x: x % 2 == 0, data))
)
# 220

Is this readable? Not really. This is where list comprehensions often win.

Lambda Functions

Lambdas are anonymous functions—useful for short, throwaway operations:

add = lambda x, y: x + y
add(2, 3)  # 5

When to use lambdas:

  • As arguments to sorted(), map(), filter(), reduce()
  • For short operations that do not need a full function definition

When to avoid lambdas:

  • When the operation is complex enough to need comments
  • When you are repeating the same logic in multiple places
# Good: short, clear
sorted(names, key=lambda x: x.lower())

# Bad: too complex for a lambda
process = lambda x: [i for i in range(x) if i % 2 == 0 and i > 10]
# Just write a real function instead

List, Dict, and Set Comprehensions

Comprehensions are Python native functional approach to building collections. They are often more readable than map() and filter() chains.

List Comprehensions

# Instead of: map(lambda x: x**2, range(10))
squares = [x**2 for x in range(10)]

# Instead of: filter(lambda x: x > 5, numbers)
large_numbers = [x for x in numbers if x > 5]

Dict Comprehensions

words = ["apple", "banana", "cherry"]

# Create word -> length mapping
lengths = {word: len(word) for word in words}
# {apple: 5, banana: 6, cherry: 6}

Set Comprehensions

text = "hello world"

# Unique vowels in text
vowels = {char for char in text if char in aeiou}
# {e, o}

Partial Application with functools.partial

Partial application creates a new function with some arguments pre-filled:

from functools import partial

def power(base, exponent):
    return base ** exponent

square = partial(power, exponent=2)
cube = partial(power, exponent=3)

square(4)  # 16
cube(2)    # 8

This is useful when you need to pass a function with fixed arguments to another function, like when using sorted() with a custom key:

from functools import partial

# Create a function that always multiplies by 10
scale_by_10 = partial(map, factor=10)

# Use it with sorted
numbers = [1, 20, 3, 40]
sorted(numbers, key=scale_by_10)

When to Use These Patterns

Functional programming patterns work best when:

  1. You are transforming data through a series of operations
  2. The operations are independent—each only depends on its input
  3. You want to avoid mutating original data

Do not force functional patterns where they do not fit. A simple for loop is often clearer than a chain of map() and reduce(). The goal is readable, maintainable code—not functional purity.

See Also