About 1639 letters
About 8 minutes
A decorator is a special kind of function used to dynamically modify the behavior of another function without changing its original code.
The creation of a decorator is just like a normal function, and the usage looks like this:
@decorator
decorated_object
This is equivalent to:
decorated_object = decorator(decorated_object)
In complex projects, you may want to print logs every time a function is called. This can be easily done with a decorator:
# Define a decorator
def log(fn):
"""
Decorator to add logging functionality to a function.
Args:
fn (any): The function to be decorated.
Returns:
any: The decorated function.
"""
def wrapper(*args, **kwargs):
# Print log showing function name and parameters
print(f"Calling {fn.__name__} with args={args}, kwargs={kwargs}")
# Call the original function
return fn(*args, **kwargs)
return wrapper
# Use decorator when defining functions
@log
def add(x: int, y: int):
return x + y
@log
def sub(x: int, y: int):
return x - y
# Call functions
add(1, 1)
add(1, 2)
sub(3, 4)
In the above decorator example, the inner function wrapper
captures the variable fn
from its enclosing scope.
Even after the outer function log
has finished execution, when wrapper
is called, it still has access to fn
.
This combination of a function along with its referencing environment is called a closure.
The captured variables are called upvalues (or free variables).
Created in 5/15/2025
Updated in 5/21/2025