What Are Python Decorators?

Mateen Kiani

Mateen Kiani

Published on Mon Aug 11 2025·2 min read

what-are-python-decorators?-a-developer’s-guide

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.


Mateen Kiani
Mateen Kiani
kiani.mateen012@gmail.com
I am a passionate Full stack developer with around 4 years of experience in MERN stack development and 1 year experience in blockchain application development. I have completed several projects in MERN stack, Nextjs and blockchain, including some NFT marketplaces. I have vast experience in Node js, Express, React and Redux.