The Py Hub

Ten useful Python decorators, with real examples

Guides7 min read5 May 2026

By · Published · Updated

Ten genuinely useful Python decorators from the standard library, with short examples: caching, properties, dataclasses, context managers, single dispatch and more, plus how to write your own and what decorators can't do for concurrency.

A decorator is a function that wraps another function or class to change its behaviour, applied with the @ syntax. Python's standard library includes several that save real time. Here are ten worth knowing, then how to write your own.

1. @functools.lru_cache and @functools.cache

These remember results for given arguments, so repeat calls are instant. lru_cache (Python 3.2+) keeps a limited number of results; cache (3.9+) is unbounded.

from functools import cache

@cache
def fib(n):
    return n if n < 2 else fib(n - 1) + fib(n - 2)

Only use caching for functions whose result depends solely on their arguments, and whose arguments are hashable.

2. @property

Lets a method be accessed like an attribute, useful for computed values or validation.

class Order:
    def __init__(self, net, vat_rate=0.20):
        self.net, self.vat_rate = net, vat_rate

    @property
    def gross(self):
        return round(self.net * (1 + self.vat_rate), 2)

3. @functools.cached_property

Like @property, but computes the value once per instance and stores it (3.8+). Ideal for expensive calculations on objects that don't change.

4. @dataclasses.dataclass

Generates __init__, __repr__ and comparison methods from type-annotated fields (3.7+).

from dataclasses import dataclass

@dataclass(frozen=True)
class Point:
    x: float
    y: float

frozen=True makes instances immutable and hashable.

5. @classmethod and 6. @staticmethod

@classmethod receives the class rather than an instance, which is perfect for alternative constructors such as Point.from_tuple(). @staticmethod receives neither; it's a plain function grouped with the class.

7. @contextlib.contextmanager

Turns a generator into a context manager for use with with, without writing a class.

from contextlib import contextmanager
import time

@contextmanager
def timer(label):
    start = time.perf_counter()
    try:
        yield
    finally:
        print(f"{label}: {time.perf_counter() - start:.3f}s")

8. @functools.singledispatch

Lets one function behave differently depending on the type of its first argument (3.4+), a tidy alternative to long isinstance chains.

9. @functools.wraps

Use it inside your own decorators, so the wrapped function keeps its name, docstring and signature for debugging and documentation tools.

10. @typing.override

Marks a method as overriding a parent class method (3.12+). Type checkers then warn you if the parent method is renamed or removed.

Writing your own: a simple retry decorator

import functools, time

def retry(times=3, delay=1.0, exceptions=(Exception,)):
    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            for attempt in range(1, times + 1):
                try:
                    return func(*args, **kwargs)
                except exceptions:
                    if attempt == times:
                        raise
                    time.sleep(delay)
        return wrapper
    return decorator

Retry only operations that are safe to repeat, such as reading from a network API, and catch specific exceptions rather than all of them.

Decorator tips

What decorators can't do: concurrency?

Decorators change how functions are called; they don't make code run in parallel by themselves. For concurrency, use the standard library directly:

Python 3.13 introduced an experimental free-threaded build without the GIL (PEP 703), but the standard build still has it, and many libraries are still adapting.

Sources and further reading

Facts checked on 20 October 2026. Spotted an error? Tell us and we will correct it.

Real-World Applications of Python Decorators for Concurrency and Parallel Processing

Distributed systems, high-performance computing, cloud computing - these are just a few areas where concurrency and parallel processing are crucial. In this section, we'll explore how Python decorators can be used in real-world applications.

1. Web Development: Using @functools.lru_cache for Optimized Caching

When developing web applications, caching is essential for improving performance. The @functools.lru_cache decorator can be used to implement optimized caching mechanisms.

2. Machine Learning: Using @functools.singledispatch for Optimized Model Deployment

In machine learning, deploying models can be a time-consuming process. The @functools.singledispatch decorator can be used to optimize model deployment by reducing the number of function definitions.

3. Scientific Computing: Using @functools.total_ordering for Optimized Data Analysis

In scientific computing, data analysis is crucial for understanding complex phenomena. The @functools.total_ordering decorator can be used to optimize data analysis by defining a total order on data structures.

4. Parallel Processing: Using @functools.lru_cache for Optimized Computation

Parallel processing is essential for large-scale computations. The @functools.lru_cache decorator can be used to optimize computation by reducing redundant calculations.

Best Practices for Using Python Decorators for Concurrency and Parallel Processing

Using Python decorators effectively requires attention to detail and a solid understanding of concurrency and parallel processing concepts. In this section, we'll explore best practices for using Python decorators.

1. Understand the Basics of Concurrency and Parallel Processing

Before using Python decorators, it's essential to understand the basics of concurrency and parallel processing. Familiarize yourself with threading, multiprocessing, and asynchronous programming concepts.

2. Choose the Right Decorator for Your Use Case

Python decorators come in various flavors, and choosing the right one depends on your use case. Familiarize yourself with different decorator types, such as @functools.lru_cache, @functools.singledispatch, and @functools.total_ordering.

3. Optimize Functionality Using Memoization

Memoization is an optimization technique that stores the results of expensive function calls to avoid redundant calculations. The @functools.lru_cache decorator can be used for memoization.

4. Use Single-Dispatch Generic Functions for Optimized Model Deployment

Single-dispatch generic functions can be used to optimize model deployment by reducing the number of function definitions.

Common Pitfalls to Avoid When Using Python Decorators for Concurrency and Parallel Processing

Using Python decorators can be an effective way to improve concurrency and parallel processing in real-world applications. However, common pitfalls can lead to performance issues, bugs, or even crashes.

1. Incorrectly Using the GIL for Threading

The Global Interpreter Lock (GIL) is a critical component of Python's threading model. However, incorrectly using the GIL for threading can lead to performance issues and bugs.

2. Not Handling Exceptions Properly

Exceptions can occur in concurrent and parallel processing applications, and not handling them properly can lead to performance issues or crashes.

3. Not Using Concurrency Primitives Efficiently

Concurrency primitives like threads, processes, and futures can be used inefficiently in Python applications.

  • Example usage: from concurrent.futures import ThreadPoolExecutor; with ThreadPoolExecutor(max_workers=4) as executor:

Real-World Example: Using Python Decorators for Concurrency and Parallel Processing in a Web Application

In this section, we'll explore how to use Python decorators for concurrency and parallel processing in a real-world web application.

Case Study: Optimizing an E-commerce Website using Concurrency and Parallel Processing

An e-commerce website can benefit from using concurrency and parallel processing to optimize performance. We'll explore how to use Python decorators to achieve this.

Conclusion

In this article, we've explored the essential Python decorators for mastering concurrency and parallel processing in real-world applications. We've covered various topics, including memoization, single-dispatch generic functions, and concurrency primitives.

References

This article has been influenced by various sources, including Python documentation, academic papers, and online resources.

Frequently Asked Questions

In this section, we'll answer frequently asked questions about using Python decorators for concurrency and parallel processing.

Get the next guide first

New articles land every week. Follow along by RSS or bookmark the homepage.

Follow by RSS