Anik Sikder
Technical Writing/python/python-and-the-magic-of-first-class-functions
article.sh

$ open article

python

Python First-Class Functions Explained: Lambdas, Callables, Partial Functions, and Functional Programming

9 min readAugust 24, 2025
Python First-Class Functions and Functional Programming Concepts

Hey Python enthusiasts! 👋

Have you ever passed a function into another function and thought:

"Wait... functions can do that?"

Or maybe you've seen things like:

code
sorted(users, key=lambda user: user["age"])

and wondered why functions are being treated like values.

Welcome to the world of First-Class Functions — one of Python's most elegant and powerful features.

Once you understand this concept, you'll start seeing why frameworks, decorators, callbacks, middleware, and many advanced Python patterns work the way they do.

Let's dive in. 🚀

What Are First-Class Functions?

A programming language supports first-class functions when functions can be treated like any other value.

In Python, functions can:

  • Be assigned to variables
  • Be passed as arguments
  • Be returned from other functions
  • Be stored in data structures
  • Be created dynamically

In other words:

Functions are objects.

Let's see what that means in practice.

Functions as Values

Consider this example:

code
def greet(name):
    return f"Hello, {name}!"

say_hi = greet

print(say_hi("Sara"))

Output:

code
Hello, Sara!

Notice something interesting?

We never called greet() directly.

Instead, we assigned the function itself to another variable.

Both names point to the same function object.

This is the foundation of first-class functions.

Passing Functions as Arguments

Because functions are objects, we can pass them around like any other value.

code
def greet(name):
    return f"Hello, {name}!"

def make_loud(func, name):
    return func(name).upper()

print(make_loud(greet, "Sara"))

Output:

code
HELLO, SARA!

Here:

  • greet becomes an argument
  • make_loud receives it
  • Then executes it

This pattern appears everywhere in Python.

Why This Matters

Many Python built-ins rely on first-class functions.

Examples:

code
sorted()
map()
filter()
reduce()
min()
max()

All of them accept functions as arguments.

Without first-class functions, these APIs wouldn't exist in their current form.

Docstrings and Type Annotations

When functions become data, documentation becomes even more important.

Consider:

code
from typing import Callable, List

def transform(
    values: List[int],
    fn: Callable[[int], float]
) -> List[float]:
    """Apply a function to every value."""
    
    return [fn(v) for v in values]

Two things help here:

Docstrings

Explain:

  • Purpose
  • Usage
  • Expected behavior

Type Annotations

Describe:

  • Inputs
  • Outputs
  • Function signatures

Benefits include:

  • Better IDE support
  • Improved readability
  • Easier maintenance
  • More reliable APIs

Lambda Functions

Sometimes creating a full function feels excessive.

That's where lambda expressions shine.

code
square = lambda x: x * x

print(square(6))

Output:

code
36

Lambdas are anonymous functions designed for simple one-line operations.

Lambdas in Real Life

A common example is sorting.

code
products = [
    {"name": "Keyboard", "price": 59},
    {"name": "Mouse", "price": 20},
    {"name": "Monitor", "price": 199},
]

sorted_products = sorted(
    products,
    key=lambda p: p["price"]
)

Instead of defining a separate function, we create it inline.

Clean and concise.

The Fun Shuffle Trick

Because functions can be passed into sorted(), people occasionally get creative.

code
import random

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

shuffled = sorted(
    data,
    key=lambda _: random.random()
)

This effectively randomizes the ordering.

Does it work?

Yes.

Should you use it?

Usually not.

For real-world shuffling:

code
random.shuffle(data)

is more efficient and more readable.

Still, it's a fun demonstration of functional flexibility.

Function Introspection

Python lets you inspect functions at runtime.

code
import inspect

def price_with_tax(
    price: float,
    rate: float = 0.1
) -> float:
    """Calculate total price."""
    
    return price * (1 + rate)

Now let's inspect it:

code
print(price_with_tax.__name__)
print(price_with_tax.__annotations__)
print(inspect.signature(price_with_tax))

Output:

code
price_with_tax

{
    'price': float,
    'rate': float,
    'return': float
}

(price: float, rate: float = 0.1) -> float

This capability powers:

  • Django
  • FastAPI
  • Click
  • Typer
  • Dependency injection frameworks
  • Automatic documentation systems

Functions Aren't the Only Callables

In Python, anything implementing __call__() becomes callable.

Example:

code
class Counter:
    def __init__(self):
        self.count = 0

    def __call__(self):
        self.count += 1
        return self.count

Usage:

code
c = Counter()

print(c())
print(c())

Output:

code
1
2

It behaves like a function while maintaining internal state.

This pattern can be surprisingly elegant.

Map, Filter, and Zip

These utilities embrace first-class functions.

Map

Transform every item.

code
names = ["anik", "sara", "lee"]

proper = list(
    map(str.title, names)
)

Output:

code
['Anik', 'Sara', 'Lee']

Filter

Keep matching items.

code
scores = [95, 45, 82]

passed = list(
    filter(
        lambda s: s >= 60,
        scores
    )
)

Output:

code
[95, 82]

Zip

Combine sequences.

code
students = [
    "Anik",
    "Sara",
    "Lee"
]

grades = [95, 88, 77]

paired = list(
    zip(students, grades)
)

Output:

code
[
    ('Anik', 95),
    ('Sara', 88),
    ('Lee', 77)
]

List Comprehensions vs Map

Many Python developers prefer comprehensions:

code
proper = [
    n.title()
    for n in names
]

Compared to:

code
map(str.title, names)

Both are valid.

Choose whichever improves readability.

Reduce: Folding Data Into One Value

Sometimes you want one final result.

That's where reduce() comes in.

code
from functools import reduce
from operator import mul

nums = [2, 3, 4]

product = reduce(
    mul,
    nums,
    1
)

Output:

code
24

Think of reduce as repeatedly combining values until only one remains.

Partial Functions

Sometimes you repeatedly call a function with the same arguments.

Enter partial().

code
from functools import partial

def add_tax(price, rate):
    return price * (1 + rate)

bd_tax = partial(
    add_tax,
    rate=0.15
)

Now:

code
print(bd_tax(100))

Output:

code
115.0

The tax rate is permanently pre-filled.

This is extremely useful in:

  • APIs
  • Logging
  • Data processing pipelines
  • Configuration-heavy systems

The Operator Module

Many lambdas can be replaced with optimized helpers.

Instead of:

code
lambda city: city["pop"]

Use:

code
from operator import itemgetter

largest = max(
    cities,
    key=itemgetter("pop")
)

Benefits:

  • More readable
  • Slightly faster
  • Purpose-built

Useful tools include:

code
itemgetter()
attrgetter()
methodcaller()

Why First-Class Functions Matter

Many Python features depend on them.

Examples include:

  • Decorators
  • Callbacks
  • Middleware
  • Event systems
  • Dependency injection
  • Functional pipelines
  • Framework internals

Without first-class functions, modern Python would look very different.

TL;DR Quick Recap

  • Functions are objects.
  • Functions can be assigned to variables.
  • Functions can be passed as arguments.
  • Functions can be returned from functions.
  • Lambdas create anonymous functions.
  • Callables aren't limited to functions.
  • map(), filter(), and reduce() leverage first-class functions.
  • partial() creates specialized functions.
  • The operator module provides functional shortcuts.
  • First-class functions power many advanced Python patterns.

Final Thoughts

First-class functions are one of Python's greatest strengths.

At first they seem like a neat trick.

But once you begin using them consistently, you'll discover they unlock a more expressive way of writing software.

Instead of building rigid systems, you start composing behavior itself.

That's where Python becomes incredibly elegant.

Functions stop being merely things you call.

They become data you can move, combine, customize, and reuse.

And that's a superpower worth mastering. ⚡

A Little Joke to End On

Why did the Python function get promoted?

Because it was outstanding in its field... and passed every callback interview. 😄


Frequently Asked Questions

What is a first-class function in Python?

A first-class function is a function that can be treated like any other object.

It can be assigned to variables, passed as arguments, returned from functions, and stored in data structures.


Are functions objects in Python?

Yes.

Functions are full-fledged objects and support attributes, introspection, and assignment.


What is the difference between a function and a callable?

A callable is anything that can be invoked using parentheses.

Functions are callable, but classes implementing __call__() are callable too.


When should I use lambda functions?

Lambdas are useful for short, simple functions that are used temporarily, especially with:

  • sorted()
  • map()
  • filter()

Are lambdas faster than normal functions?

No.

Lambdas are primarily a syntax convenience.

Performance differences are negligible.


What does functools.partial do?

partial() creates a new function with some arguments already filled in.

This helps reduce repetition and simplify APIs.


What is function introspection?

Function introspection is the ability to inspect metadata about a function, including:

  • Name
  • Signature
  • Annotations
  • Docstrings

Why does FastAPI use type annotations?

FastAPI uses introspection and annotations to automatically:

  • Validate inputs
  • Generate API documentation
  • Create schemas

What is the operator module used for?

The operator module provides optimized helpers such as:

code
itemgetter()
attrgetter()
methodcaller()

which often replace small lambda functions.


Should I use map and filter or list comprehensions?

Both are valid.

Many Python developers prefer comprehensions because they're often easier to read.

Choose whichever improves clarity.


Why are first-class functions important?

They enable:

  • Decorators
  • Functional programming
  • Flexible APIs
  • Reusable behaviors
  • Framework abstractions

and many advanced Python design patterns.


Key Takeaways

  • Functions are objects in Python.
  • Functions can be passed, returned, and stored.
  • Lambdas provide lightweight anonymous functions.
  • Callables extend function-like behavior to objects.
  • Introspection allows runtime inspection of functions.
  • map, filter, reduce, and partial embrace first-class functions.
  • The operator module offers useful functional shortcuts.
  • First-class functions power many of Python's most powerful abstractions.

If you found this article useful, share it with fellow Python developers and follow for more deep dives into Python internals and software engineering concepts.


About the Author

Anik Sikder is a Software Engineer specializing in Backend Systems, SaaS Architecture, Cloud Infrastructure, Python, Django, FastAPI, and scalable software engineering.

He writes about Python, JavaScript, system design, distributed systems, software architecture, and modern engineering practices.

$ tags

pythonfirst-class-functionslambdafunctional-programmingcallablesfunctoolspython-tipssoftware-engineering

$ ls related_articles

status: end_of_file