Higher Order Functions#
A higher-order function (HOF) takes functions as arguments and/or returns functions. Python treats functions as first-class values — HOFs are idiomatic, not academic.
How to use this page
Pair with Lambda Functions, Partial Functions, Map, Filter and Reduce.
At a glance
| Track | Python Advanced → Advanced Functions |
| Sections | 6 major topics |
| Outline | Use the right-hand TOC to jump |
Topics: First-class functions · Functions as arguments · Functions as return values · Composition · Callbacks and strategy pattern · HOF vs OOP
- First-class functions
- Functions as arguments
- Functions as return values
- Composition
- Callbacks and strategy pattern
- HOF vs OOP
First-class functions#
def greet():
return "Hello"
say = greet # assign
call = lambda f: f() # pass
result = call(greet) # invoke via variable
Functions are objects with identity, attributes, and methods.
Functions as arguments#
def apply(fn, value):
return fn(value)
apply(abs, -5) # 5
apply(lambda x: x * 2, 10) # 20
def run_twice(fn, arg):
fn(arg)
fn(arg)
Built-in HOFs#
| Function | Purpose |
|---|---|
sorted(it, key=fn) |
Sort by key function |
max(it, key=fn) |
Maximum by key |
map(fn, it) |
Transform (lazy iterator) |
filter(fn, it) |
Filter (lazy iterator) |
any / all |
Short-circuit predicates |
Functions as return values#
def make_validator(min_val: int, max_val: int):
def validate(x: int) -> bool:
return min_val <= x <= max_val
return validate
is_percent = make_validator(0, 100)
is_percent(50) # True
Factory pattern — see Closures.
Composition#
Combine small functions into pipelines:
def compose(f, g):
return lambda x: f(g(x))
double = lambda x: x * 2
inc = lambda x: x + 1
double_then_inc = compose(inc, double)
double_then_inc(3) # 7
# Manual pipeline
def pipeline(x, *fns):
for fn in fns:
x = fn(x)
return x
Modern alternative: explicit steps or comprehensions when pipeline is short.
Callbacks and strategy pattern#
def process_items(items, on_item, on_error=None):
for item in items:
try:
on_item(item)
except Exception as e:
if on_error:
on_error(item, e)
else:
raise
process_items([1, 2, 0], on_item=lambda x: print(10 / x))
HOF replaces subclassing for simple strategy selection.
HOF vs OOP#
| HOF | Class with methods |
|---|---|
| Lightweight | Structured state |
| Functional style | Inheritance |
| Great for single callback | Many related behaviors |
Interviews: either works — prefer clarity.
Interview traps (quick reference)#
| Trap | What goes wrong | Safe approach |
|---|---|---|
Side effects in key= |
Sort mutates or logs unexpectedly | Pure key functions |
map in Py3 |
Returns iterator — use once | list(map(...)) or comprehension |
| Over-abstraction | Unreadable one-liners | Name intermediate functions |
| Late binding in loop callbacks | Wrong captured variable | Factory or default arg |
Mental model checklist#
- What makes a function "higher-order"?
- How is
sorted(key=...)a HOF? - When is returning a function better than a class?
- What is function composition?
What's next#
| Topic | Page |
|---|---|
| Lambdas | Lambda Functions |
| Partial | Partial Functions |
| Map/filter/reduce | Map, Filter and Reduce |
| Closures | Closures |