Skip to main content
Python treats functions as first-class objects, which means you can assign them to variables, pass them as arguments, return them from other functions, and store them in data structures. This single fact unlocks closures, decorators, and an enormous amount of elegant, reusable code. This page takes you from that foundation all the way through writing production-quality decorators.

Functions as First-Class Objects

Variable-Length Arguments

When you don’t know in advance how many arguments a function will receive, use *args for positional arguments and **kwargs for keyword arguments.

Closures

A closure is an inner function that remembers variables from its enclosing scope even after the outer function has finished executing. Three conditions create a closure:
  1. There is a nested function.
  2. The nested function references a variable from the enclosing function.
  3. The enclosing function returns the nested function.
Closures are powerful because each call to make_multiplier creates an independent function that permanently carries its own factor.

Real-world closure: a configurable validator

Decorators

A decorator wraps a function to extend its behaviour without changing its source code. Under the hood it is a higher-order function: it receives the original function, defines a wrapper that adds behaviour around it, and returns the wrapper.
The @my_decorator syntax is just shorthand for add = my_decorator(add).

Preserving function metadata with functools.wraps

Without functools.wraps, the wrapper replaces the original function’s name and docstring. Always use @wraps when writing decorators.

Decorator with arguments

To pass arguments to a decorator, add an extra layer of nesting — a function that returns the decorator:

Built-in Decorators

Python ships with three decorator-like tools that you will use frequently on class methods:
A static method belongs to the class’s namespace but receives no automatic first argument. Use it for utility functions logically grouped with the class but not dependent on instance or class state.
A class method receives the class itself as its first argument (cls). Use it to define alternative constructors.
A property lets you define a method that is accessed like an attribute. Pair it with @name.setter to add validation on assignment.

Practical Decorator Examples