What Are Python Decorators?

Introduction
Python decorators play a key role in extending and modifying behavior of functions or classes without changing their code. They act like wrappers that you place around functions using the @ symbol. This pattern helps you write cleaner, more readable code by separating concerns.
What Are Decorators?
A decorator is a function that takes another function and returns a new function with added behavior. In Python, you apply a decorator with @decorator_name
above your function. Internally, it transforms:
@decorator
func()
into:
func = decorator(func)
Why Use Decorators?
You often need to add common functionality—logging, timing, authentication—to many functions. Decorators let you wrap these cross-cutting concerns once and reuse them. This keeps your code DRY and lets you apply changes consistently.
Under the Hood of Decorators
Decorators leverage Python's first-class functions and closures. Since functions are objects, you can pass them as arguments and return them. Closures let the inner wrapper function remember the original function and its environment, preserving state across calls.
Creating a Simple Decorator
def my_decorator(func):
def wrapper():
print("Before calling", func.__name__)
func()
print("After calling", func.__name__)
return wrapper
@my_decorator
def say_hello():
print("Hello")
say_hello()
Decorators with Arguments
To write decorators that accept arguments, add one more nesting level:
def repeat(n):
def decorator(func):
def wrapper(*args, **kwargs):
for _ in range(n):
func(*args, **kwargs)
return wrapper
return decorator
@repeat(3)
def greet(name):
print(f"Hello {name}")
greet("Alice")
Decorating Classes
You can apply decorators to classes just like functions. A class decorator takes a class, modifies or wraps it, and returns the new version. For example, you can auto-register classes on import.
def singleton(cls):
instances = {}
def getinstance(*args, **kwargs):
if cls not in instances:
instances[cls] = cls(*args, **kwargs)
return instances[cls]
return getinstance
@singleton
class Logger:
pass
Built-in Decorators
Python ships with several decorators:
@staticmethod
: define methods that don’t access instance data.@classmethod
: define methods that access the class itself.@property
: expose methods like attributes.
Best Practices
Tip: Always use
functools.wraps
to preserve metadata of the original function.
- Keep decorators focused on a single purpose.
- Document side effects clearly in your code.
- Avoid complex logic in decorators to keep readability.
For method overriding scenarios, see the Python Override Decorator Guide. Before naming your decorated functions, check function naming best practices.
Subscribe to my newsletter
Read articles from Mateen Kiani directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
