Mateen Kiani
Published on Mon Aug 11 2025·2 min read
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.
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:
@decoratorfunc()
into:
func = decorator(func)
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.
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.
def my_decorator(func):def wrapper():print("Before calling", func.__name__)func()print("After calling", func.__name__)return wrapper@my_decoratordef say_hello():print("Hello")say_hello()
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 wrapperreturn decorator@repeat(3)def greet(name):print(f"Hello {name}")greet("Alice")
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@singletonclass Logger:pass
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.Tip: Always use
functools.wraps
to preserve metadata of the original function.
For method overriding scenarios, see the Python Override Decorator Guide. Before naming your decorated functions, check function naming best practices.