What you'll learn
In Python, functions are first-class objects — you can store them, pass them, and return them like any value. That unlocks a powerful, expressive style: functional programming. It's the foundation for decorators (next module) and for clean data transformations.
By the end you'll be able to:
- Treat functions as first-class objects
- Write higher-order functions
- Use
map,filter, andreduce - Understand closures and reach for
functools
Functions as objects
A function is a value. You can assign it to a variable, put it in a list or dict, and pass it around — without calling it (no parentheses). This is the idea everything else in this module builds on:
def shout(text):
return text.upper() + "!"
greet = shout # assign a function to a variable
print(greet("hi"))
funcs = [str.upper, str.lower, str.title] # functions in a list
for f in funcs:
print(f("Hello World"))Higher-order functions
A higher-order function takes a function as an argument, returns one, or both. This lets you parameterize behavior, not just data — the caller decides what happens:
def apply_twice(func, value): # takes a function as an argument
return func(func(value))
def add_three(x):
return x + 3
print(apply_twice(add_three, 10)) # 10 -> 13 -> 16
print(apply_twice(lambda s: s + "!", "hi"))map, filter & reduce
The classic functional trio transforms sequences. map applies a function to every item, filter keeps items matching a predicate, and reduce (from functools) folds a sequence into a single value:
from functools import reduce
nums = [1, 2, 3, 4, 5, 6]
evens = list(filter(lambda n: n % 2 == 0, nums))
squared = list(map(lambda n: n * n, nums))
total = reduce(lambda acc, n: acc + n, nums, 0)
print(evens)
print(squared)
print(total)
# Often a comprehension is clearer than map/filter:
print([n * n for n in nums if n % 2 == 0])Tip
map/filter with a lambda — compare the last line above. Reach for map/filter mainly when you already have a named function to apply; otherwise a comprehension usually reads better.Closures
When an inner function remembers variables from the enclosing function even after that function has returned, it's a closure. It "closes over" those values — a clean way to build specialized functions and the mechanism behind decorators:
def make_multiplier(factor): # 'factor' is captured by the inner function
def multiply(x):
return x * factor # closure remembers factor
return multiply
double = make_multiplier(2)
triple = make_multiplier(3)
print(double(10)) # 20
print(triple(10)) # 30Key idea
double and triple are the same inner function, but each carries its own captured factor. Closures let a function bundle together some remembered state with its behavior — without needing a class.functools
The functools module is a treasure chest. partial pre-fills some arguments to make a specialized version of a function; lru_cache memoizes results so repeated calls are instant; and wraps (next module) preserves metadata on wrapped functions:
from functools import partial, lru_cache
# partial: pre-fill some arguments
def power(base, exp):
return base ** exp
square = partial(power, exp=2)
print(square(5)) # 25
# lru_cache: memoize expensive calls automatically
@lru_cache
def fib(n):
return n if n < 2 else fib(n - 1) + fib(n - 2)
print(fib(30)) # fast, thanks to cachingRecap & quick check
Key takeaways
- Functions are first-class objects: assign, store, and pass them without calling them.
- Higher-order functions take and/or return functions, parameterizing behavior.
- map applies a function to each item, filter keeps matches, functools.reduce folds to one value.
- A closure is an inner function that remembers variables from its enclosing scope.
- functools helps: partial pre-fills arguments, lru_cache memoizes results.
Quick check
1. What does 'functions are first-class objects' mean?
2. A higher-order function is one that…
3. What does map(f, seq) do?
4. What is a closure?
5. What does functools.lru_cache do?
Closures and higher-order functions lead directly to one of Python's most beloved features. Next up: Module 24 — Decorators.