Python Decorators: What They Are, How They Work, and Why C Doesn’t Have Them
In Python, decorators are a powerful feature for applying common logic to multiple functions without duplicating code. They allow you to extend or modify the behavior of functions, methods, or classes in a declarative and clean way.
What Is a Decorator?
A decorator is a function that takes another function as input and returns a new function that usually wraps the original one. In practice, decorators are used to implement cross-cutting concerns like logging, error handling, validation, access control, and performance monitoring.
def decorator(func):
def wrapper(*args, **kwargs):
print("Before execution")
result = func(*args, **kwargs)
print("After execution")
return result
return wrapper
@decorator
def greet(name):
print(f"Hello, {name}")
greet("World")
Output:
Before execution
Hello, World
After execution
This is functionally equivalent to:
greet = decorator(greet)
Parameterized Decorators
Decorators can also accept parameters by using a higher-order function that returns the actual decorator.
def decorator_with_args(prefix):
def decorator(func):
def wrapper(*args, **kwargs):
print(f"{prefix}: before execution")
return func(*args, **kwargs)
return wrapper
return decorator
@decorator_with_args("DEBUG")
def add(a, b):
return a + b
Decorators for Methods
Decorators also work with class methods. The decorator needs to preserve the method signature, including self or cls as the first argument.
def log(func):
def wrapper(self, *args, **kwargs):
print(f"Calling {func.__name__}")
return func(self, *args, **kwargs)
return wrapper
class Calculator:
@log
def add(self, a, b):
return a + b