Understanding Python Decorators: Concepts, Examples, and Advanced Usage
This article explains Python decorators as higher‑order functions that can modify or extend the behavior of functions and classes, covering their definition, application with @ syntax, parameterized and class decorators, built‑in decorators, multiple decorator ordering, and includes clear code examples.
Decorators are a powerful Python feature that let developers modify or enhance the behavior of functions and methods without altering their source code; they are higher‑order functions that accept a function and return a new or wrapped function, enabling tasks such as logging, access control, and performance measurement while keeping code modular.
The basic workflow involves defining a decorator function that returns an inner wrapper (often a closure), applying it to a target function with the @decorator_name syntax placed above the function definition, and understanding that calling the decorated function actually invokes the wrapper, which can execute additional logic before or after the original function.
Example of a simple decorator:
def my_decorator(func):
def wrapper():
print("Something is happening before the function is called.")
func()
print("Something is happening after the function is called.")
return wrapper
@my_decorator
def say_hello():
print("Hello!")
say_hello()
# Output:
# Something is happening before the function is called.
# Hello!
# Something is happening after the function is called.Parameterized decorators (decorator factories) allow the decorator itself to accept arguments; the outer function receives the parameters and returns the actual decorator, which then wraps the target function.
def repeat(num_times):
def decorator_repeat(func):
def wrapper(*args, **kwargs):
for _ in range(num_times):
result = func(*args, **kwargs)
return result
return wrapper
return decorator_repeat
@repeat(num_times=3)
def greet(name):
print(f"Hello {name}")
greet("Alice")
# Output:
# Hello Alice
# Hello Alice
# Hello AliceClass decorators work similarly but receive a class object, allowing dynamic modification of class attributes or methods.
def add_method(cls):
def decorator(func):
setattr(cls, func.__name__, func)
return cls
return decorator
@add_method
class MyClass:
pass
@add_method(MyClass)
def new_method(self):
print("This is a dynamically added method.")
obj = MyClass()
obj.new_method()
# Output: This is a dynamically added method.Python also provides built‑in decorators such as @classmethod, @staticmethod, @property, @functools.lru_cache, and @dataclasses.dataclass. For example, using @property to create a managed attribute:
class Circle:
def __init__(self, radius):
self._radius = radius
@property
def radius(self):
"""The radius property."""
print("Getting radius")
return self._radius
@radius.setter
def radius(self, value):
if value >= 0:
self._radius = value
else:
raise ValueError("Radius must be non-negative")
circle = Circle(5)
print(circle.radius) # Output: Getting radius\n5
circle.radius = 10
print(circle.radius) # Output: Getting radius\n10When multiple decorators are stacked on a function, they are applied from the bottom up; the decorator closest to the function definition runs first.
def decorator_one(func):
def wrapper():
print("Decorator one")
func()
return wrapper
def decorator_two(func):
def wrapper():
print("Decorator two")
func()
return wrapper
@decorator_one
@decorator_two
def hello():
print("Hello!")
hello()
# Output:
# Decorator one
# Decorator two
# Hello!In summary, Python decorators provide a flexible and elegant mechanism to extend or modify functions and classes, enabling developers to write cleaner, more maintainable, and feature‑rich code; mastering their usage opens the door to advanced patterns and best practices.
Test Development Learning Exchange
Test Development Learning Exchange
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.