Skip to content

How to Apply Higher-Order Functions in Python

Learn how to use Python's higher-order functions like map, filter, and decorators to write cleaner, more modular code with practical examples.

In Python, functions are "first-class citizens," meaning they can be assigned to variables, passed as arguments, and returned from other functions. A Higher-Order Function (HOF) is simply a function that operates on other functions, either by taking them as arguments or by returning them.

This guide explores how to leverage HOFs to write cleaner, more modular, and efficient code using built-in tools like map, filter, and the functools library.

Passing Functions as Arguments (map, filter)

The most common application of HOFs is data transformation. Instead of writing explicit loops to process lists, you pass a transformation function to a HOF.

Using map() for Transformation

map() applies a function to every item in an iterable.

def square(x):
    return x ** 2

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

squared_loop = []
for num in numbers:
    squared_loop.append(square(num))

squared_map = list(map(square, numbers))

print(f"Loop result: {squared_loop}")
print(f"Map result:  {squared_map}")

Output:

Loop result: [1, 4, 9, 16, 25]
Map result:  [1, 4, 9, 16, 25]

Using sorted() with a Key

The built-in sorted() function is a HOF because it accepts a key argument, i.e. a function that determines how to sort elements.

words = ["apple", "Banana", "cherry", "Date"]

print(f"Standard sort: {sorted(words)}")

print(f"HOF sort:      {sorted(words, key=str.lower)}")

Output:

Standard sort: ['Banana', 'Date', 'apple', 'cherry']
HOF sort:      ['apple', 'Banana', 'cherry', 'Date']

Returning Functions (Closures and Factories)

A HOF can create and return a new function. This is useful for creating "function factories" that configure a function with specific behaviors (Closures).

def make_multiplier(factor):
    """Higher-Order Function that returns a new function."""
    
    def multiplier(x):
        return x * factor
    
    return multiplier

double = make_multiplier(2)
triple = make_multiplier(3)

print(f"Double 5: {double(5)}")
print(f"Triple 5: {triple(5)}")

Output:

Double 5: 10
Triple 5: 15

Partial Function Application

Sometimes you have an existing function with many arguments, and you want to create a new version with some arguments pre-filled. The functools.partial HOF handles this automatically.

from functools import partial

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

def square_manual(base):
    return power(base, 2)

square_partial = partial(power, exponent=2)
cube_partial = partial(power, exponent=3)

print(f"Square of 4: {square_partial(4)}")
print(f"Cube of 4:   {cube_partial(4)}")

Output:

Square of 4: 16
Cube of 4:   64

Decorators: The Ultimate HOF

Decorators are syntactic sugar for HOFs. A decorator is a function that takes a function as input and returns a modified function as output.

Creating a Simple Logger

import functools

def logger(func):
    """A HOF that adds logging to any function."""
    @functools.wraps(func) # Preserves original function metadata
    def wrapper(*args, **kwargs):
        print(f"LOG: Running {func.__name__}")
        result = func(*args, **kwargs)
        print(f"LOG: Finished {func.__name__}")
        return result
    return wrapper

@logger
def add(x, y):
    return x + y

print(f"Result: {add(5, 3)}")

Output:

LOG: Running add
LOG: Finished add
Result: 8

Conclusion

Higher-Order Functions allow you to abstract logic and behavior, making your code more reusable and declarative.

  1. Pass Functions: Use map, filter, and sorted to apply logic to data collections.
  2. Return Functions: Use closures to create configurable function factories.
  3. Partial Application: Use functools.partial to fix arguments and simplify function signatures.
  4. Decorators: Use @decorator syntax to wrap functions with common behavior like logging or caching.
Navigation