datarekha
Python Easy Asked at GoogleAsked at MetaAsked at Amazon

What does it mean for functions to be first-class objects in Python?

The short answer

First-class functions can be stored in variables, passed as arguments, returned from other functions, and placed in data structures — just like any other object. This is the foundation for higher-order functions, decorators, callbacks, and functional programming patterns in Python.

How to think about it

“First-class” just means functions are values — full objects you can pass around like an integer or a string. In Python every function is an instance of the function type, carrying its own attributes (__name__, __doc__, __closure__). Once that clicks, decorators, callbacks, and the functional patterns stop looking like special features and start looking like ordinary object-passing.

Concretely, there are four things you can do with a function because it’s an object: store it in a variable, drop it into a data structure, pass it as an argument, and return it from another function.

A worked example

from functools import partial

def square(x):
    return x * x

# 1. Store in a variable — it's just a reference to the same object
op = square
print("op(4)        =", op(4))

# 2. Store in a data structure — a dispatch table beats a long if/elif
ops = {"sq": square, "abs": abs, "neg": lambda x: -x}
print("ops['sq'](5) =", ops["sq"](5))

# 3. Pass as an argument — a higher-order function
def apply(func, values):
    return [func(v) for v in values]
print("apply square :", apply(square, [1, 2, 3, 4]))

# 4. Return from a function — a factory / closure
def make_power(exp):
    def power(x):
        return x ** exp
    return power
cube = make_power(3)
print("cube(4)      =", cube(4))

# Fix some arguments and get a new callable back
double = partial(lambda factor, x: factor * x, 2)
print("double(7)    =", double(7))

# And functions really are objects, with attributes and a type
print("square name  :", square.__name__)
print("square type  :", type(square))
op(4)        = 16
ops['sq'](5) = 25
apply square : [1, 4, 9, 16]
cube(4)      = 64
double(7)    = 14
square name  : square
square type  : <class 'function'>

Each line is the same idea wearing a different hat. op = square copied a reference, not the code; the ops dict turned a branchy if/elif into a clean lookup; apply took behaviour as a parameter; make_power returned a freshly built function; and partial pre-filled an argument to make a new one. The last two lines are the punchline — type(square) really is <class 'function'>, an object like any other.

Patterns this unlocks

  • sorted(items, key=func) — hand the sort its criterion as a function.
  • functools.partial — freeze some arguments, get back a smaller callable.
  • Dependency injection — pass behaviour in rather than inheriting it.
  • Dispatch tables — a dict of callables in place of a long if/elif ladder.

None of these need special syntax. The language has no “callback keyword” or “strategy object” — you just pass a function. That’s the entire payoff of first-class status.

Learn it properly Functions

Keep practising

All Python questions

Explore further

Skip to content