Understanding Python Decorators: From Simple Functions to Advanced Usage
This article explains how Python decorators work by showing how to wrap functions for timing, handle arbitrary arguments, and create higher‑order decorators that can repeat calls, illustrating the power and flexibility of function wrapping in Python.
Python treats functions as first‑class objects, allowing them to be assigned to variables, passed as arguments, and returned from other functions. Decorators are essentially functions that wrap other functions to add new behavior without modifying the original function's code.
We begin with a simple add function that adds two numbers and demonstrate manual timing by inserting code before and after the call, which quickly becomes repetitive when many functions need the same behavior.
To avoid duplication, a higher‑order function timer(func) is introduced. It returns a new function f(x, y=10) that records the start time, calls the original function, records the end time, prints the elapsed time, and returns the result. By assigning add = timer(add) we achieve the same effect as a decorator.
The decorator syntax @timer is then shown, which is syntactic sugar for the assignment add = timer(add) . This makes the code clearer and more concise.
To make the decorator applicable to any function, the implementation is updated to accept arbitrary positional and keyword arguments using *args and **kwargs . This version of timer can wrap functions with any signature while preserving default values.
Finally, the concept of higher‑order decorators is demonstrated with a decorator factory ntimes(n) . It returns a decorator that repeats the wrapped function n times. An example shows @ntimes(3) applied to add , causing the function body to execute three times, and the combined use of @timer and @ntimes illustrates composability.
Key code examples:
# dec.py
def add(x, y=10):
return x + y
# Simple timer decorator
from time import time
def timer(func):
def f(*args, **kwargs):
before = time()
rv = func(*args, **kwargs)
after = time()
print('time taken:', after - before)
return rv
return f
@timer
def add(x, y=10):
return x + y
# Higher‑order decorator to repeat calls
def ntimes(n):
def inner(f):
def wrapper(*args, **kwargs):
for _ in range(n):
rv = f(*args, **kwargs)
return rv
return wrapper
return inner
@ntimes(3)
@timer
def add(x, y):
print(x + y)
return x + yPython Programming Learning Circle
A global community of Chinese Python developers offering technical articles, columns, original video tutorials, and problem sets. Topics include web full‑stack development, web scraping, data analysis, natural language processing, image processing, machine learning, automated testing, DevOps automation, and big data.
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.