A Guide to Useful Python Decorators
This article introduces several practical Python decorators—including @lru_cache, @jit, @do_twice, @count_calls, @dataclass, @singleton, @use_unit, and @singledispatch—explaining their purposes, benefits, and providing code examples to demonstrate how they can improve performance, readability, and functionality in Python programs.
Python’s flexibility is largely due to its powerful decorator feature, which can modify the behavior of functions and classes.
Below are several practical decorators, each illustrated with code examples.
1. @lru_cache
Provided by functools , @lru_cache caches the results of function calls, dramatically speeding up repeated executions such as recursive factorial calculations.
<code>def factorial(n):
return n * factorial(n-1) if n else 1
</code> <code>@lru_cache
def factorial(n):
return n * factorial(n-1) if n else 1
</code>The first few results are stored, so subsequent calls retrieve cached values instead of recomputing.
2. @jit
The Just‑In‑Time (JIT) decorator from the Numba library compiles Python code to machine code at runtime, reducing overhead and accelerating compute‑intensive tasks such as Monte Carlo π estimation.
<code>from numba import jit
import random
@jit(nopython=True)
def monte_carlo_pi(nsamples):
acc = 0
for i in range(nsamples):
x = random.random()
y = random.random()
if (x**2 + y**2) < 1.0:
acc += 1
return 4.0 * acc / nsamples
</code>3. @do_twice
This simple decorator runs the wrapped function twice, which can be handy for quick performance checks or debugging.
<code>from decorators import do_twice
@do_twice
def timerfunc():
%timeit factorial(15)
</code>4. @count_calls
Tracks how many times a function has been invoked, providing useful runtime diagnostics.
<code>from decorators import count_calls
@count_calls
def function_example():
print("Hello World!")
function_example()
function_example()
function_example()
</code>5. @dataclass
The @dataclass decorator from the dataclasses module automatically generates common special methods such as __init__ , reducing boilerplate when defining classes.
<code>from dataclasses import dataclass
@dataclass
class Food:
name: str
unit_price: float
stock: int = 0
def stock_value(self) -> float:
return self.stock * self.unit_price
</code>6. @singleton
Ensures a class has only one instance throughout a program, effectively providing a global‑like object without using module‑level variables.
<code>def singleton(cls):
instances = {}
def wrapper(*args, **kwargs):
if cls not in instances:
instances[cls] = cls(*args, **kwargs)
return instances[cls]
return wrapper
@singleton
class MyClass:
def func(self):
pass
</code>7. @use_unit
A custom decorator that attaches a physical unit (using the pint library) to a function’s return value, useful in scientific calculations.
<code>def use_unit(unit):
"""Return a Quantity with the given unit."""
use_unit.ureg = pint.UnitRegistry()
def decorator_use_unit(func):
@functools.wraps(func)
def wrapper_use_unit(*args, **kwargs):
value = func(*args, **kwargs)
return value * use_unit.ureg(unit)
return wrapper_use_unit
return decorator_use_unit
@use_unit("meters per second")
def average_speed(distance, duration):
return distance / duration
</code>8. @singledispatch
The functools.singledispatch decorator enables function overloading based on the type of the first argument, simplifying code that must handle multiple input types.
<code>@singledispatch
def fun(arg, verbose=False):
if verbose:
print("Let me just say,", end=" ")
print(arg)
@fun.register
def _(arg: int, verbose=False):
if verbose:
print("Strength in numbers, eh?", end=" ")
print(arg)
@fun.register
def _(arg: list, verbose=False):
if verbose:
print("Enumerate this:")
for i, elem in enumerate(arg):
print(i, elem)
</code>Python 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.