Master Python Decorators: From Basics to Advanced Patterns
This article walks Python developers through the concept of decorators, showing simple timing examples, how to handle functions with parameters and return values, advanced techniques like parameterized, class, stateful, and nested decorators, and provides ready-to-use code templates for real‑world use.
Practical Introduction
For Python learners who have passed the beginner stage, decorators become essential. They are used in web development, logging, performance monitoring, permission control, and are a common interview topic.
Problem Statement
Consider the following code:
def step1():
print('step1.......')
def step2():
print('step2......')
def step3():
print('step3......')
step1()
step2()
step3()The functions run sequentially, but we want to measure the execution time of each.
Brute‑Force Solution
Record start time at the beginning of the function.
Record end time after the business logic.
Subtract to obtain the duration.
Adding timing code to every function quickly becomes cumbersome.
Using a Decorator
A cleaner solution is to create a decorator that wraps the original function.
import time
def timer(func):
'''Decorator that measures function execution time.'''
def wrapper():
start = time.time()
func()
end = time.time()
used = end - start
print(f'{func.__name__} used {used}')
return wrapperThe timer function is a decorator that adds timing without modifying the original functions.
Its parameter is the function to be decorated.
It returns a new wrapper function.
The wrapper records start time, calls the original function, records end time, and prints the duration.
Applying the decorator:
@timer
def step1():
print('step1.......')
@timer
def step2():
print('step2......')
@timer
def step3():
print('step3......')
step1()
step2()
step3()Decorator Syntax Sugar
Using the @ symbol before a function automatically applies the decorator, eliminating the need to modify call sites.
import time
def timer(func):
'''Decorator that measures function execution time.'''
def wrapper():
start = time.time()
func()
end = time.time()
used = end - start
print(f'{func.__name__} used {used}')
return wrapper
@timer
def step1():
print('step1.......')
@timer
def step2():
print('step2......')
@timer
def step3():
print('step3......')
step1()
step2()
step3()Advanced Usage
Functions with Parameters
When decorating a function that accepts arguments, the wrapper must forward them:
def timer(func):
def wrapper(*args, **kwargs):
start = time.time()
func(*args, **kwargs)
end = time.time()
used = end - start
print(f'{func.__name__} used {used}')
return wrapperThis resolves the
TypeError: wrapper() takes 0 positional arguments but 1 was givenerror.
Functions with Return Values
def timer(func):
def wrapper(*args, **kwargs):
start = time.time()
ret_value = func(*args, **kwargs)
end = time.time()
used = end - start
print(f'{func.__name__} used {used}')
return ret_value
return wrapperFurther Topics
Class decorators (decorating a class’s __init__).
Multiple decorators stacked together.
Parameterised decorators (decorators that accept their own arguments).
Stateful decorators that maintain internal state.
Built‑in Decorators
Python provides several built‑in decorators such as @classmethod, @staticmethod, and @property. Example:
class Circle:
def __init__(self, radius):
self._radius = radius
@property
def radius(self):
return self._radius
@radius.setter
def radius(self, value):
if value >= 0:
self._radius = value
else:
raise ValueError('Radius must be positive')
@property
def area(self):
return self.pi() * self.radius ** 2
@classmethod
def unit_circle(cls):
return cls(1)
@staticmethod
def pi():
return 3.1415926535Creating Custom Decorators
Debug decorator that prints arguments and return value:
def debug(func):
def wrapper_debug(*args, **kwargs):
print(f'{func.__name__}: {args}, {kwargs}')
ret_val = func(*args, **kwargs)
print(f'return: {ret_val}')
return ret_val
return wrapper_debugSlow decorator that adds a delay:
def slow(func):
def wrapper_slow(*args, **kwargs):
print(f'{func.__name__} sleeping 1 second')
time.sleep(1)
return func(*args, **kwargs)
return wrapper_slowParameterised Decorator Example
def slow(seconds):
def decorator_slow(func):
def wrapper_slow(*args, **kwargs):
print(f'{func.__name__} sleeping {seconds} second')
time.sleep(seconds)
return func(*args, **kwargs)
return wrapper_slow
return decorator_slow
@slow(2)
def add(a, b):
return a + bSingleton Class Decorator
def singleton(cls):
'''Create a singleton class.'''
def single_wrapper(*args, **kwargs):
if not single_wrapper.instance:
single_wrapper.instance = cls(*args, **kwargs)
return single_wrapper.instance
single_wrapper.instance = None
return single_wrapper
@singleton
class Counter:
def __init__(self):
self._count = 0
def visit(self):
self._count += 1
print(f'visiting: {self._count}')All instances of Counter share the same state.
Stateful Decorator Example
def count(func):
def wrapper_count():
wrapper_count.count += 1
print(f'{func.__name__}: call #{wrapper_count.count}')
func()
wrapper_count.count = 0
return wrapper_countNested Decorators
def timer(func):
def wrapper():
start = time.perf_counter()
func()
end = time.perf_counter()
print(f'{func.__name__} used {end - start}')
return wrapper
@slow
@timer
def run():
print('Running')The function run first sleeps (via slow) then measures execution time (via timer).
Conclusion
Understanding decorators—from simple timing to parameterised, class‑level, stateful, and nested usage—empowers Python developers to write cleaner, more reusable code and ace interview questions that frequently involve this powerful feature.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Python Crawling & Data Mining
Life's short, I code in Python. This channel shares Python web crawling, data mining, analysis, processing, visualization, automated testing, DevOps, big data, AI, cloud computing, machine learning tools, resources, news, technical articles, tutorial videos and learning materials. Join us!
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.
