Standard List of Built-in and Core Module Decorators in Python

Python ships with decorators spread across the builtins and several standard library modules. Knowing what is available eliminates the need to reinvent patterns that the language already provides. This reference catalogs every decorator in the builtins and the core modules -- functools, dataclasses, contextlib, abc, typing, and atexit -- with a concise code example and a one-paragraph explanation for each.

Built-in Decorators (No Import Required)

Three decorators are available as builtins. They require no import and are used directly in class bodies.

@property

Converts a method into a managed attribute. The method becomes a getter, and the returned property object provides .setter and .deleter methods that can be used as decorators to define write and delete behavior:

class Temperature:
    def __init__(self, celsius):
        self._celsius = celsius

    @property
    def fahrenheit(self):
        return self._celsius * 9 / 5 + 32

    @property
    def celsius(self):
        return self._celsius

    @celsius.setter
    def celsius(self, value):
        if value < -273.15:
            raise ValueError("Below absolute zero")
        self._celsius = value

t = Temperature(100)
print(t.fahrenheit)  # 212.0
t.celsius = 0
print(t.fahrenheit)  # 32.0

@staticmethod

Removes the implicit first argument (self or cls) from a method. The method behaves like a plain function namespaced inside the class:

class MathHelper:
    @staticmethod
    def clamp(value, low, high):
        return max(low, min(value, high))

print(MathHelper.clamp(15, 0, 10))  # 10

@classmethod

Passes the class (cls) as the first argument instead of the instance. Commonly used for factory methods that produce instances through alternative constructors:

import json

class Config:
    def __init__(self, settings):
        self.settings = settings

    @classmethod
    def from_json(cls, path):
        with open(path) as f:
            return cls(json.load(f))

    @classmethod
    def defaults(cls):
        return cls({"debug": False, "log_level": "INFO"})

functools Decorators

The functools module contains the highest concentration of decorators in the standard library. All require from functools import ....

@functools.wraps

Preserves the original function's metadata when writing a decorator. Copies __name__, __doc__, __module__, __qualname__, and __annotations__ from the wrapped function onto the wrapper:

from functools import wraps

def log(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        print(f"Calling {func.__name__}")
        return func(*args, **kwargs)
    return wrapper

@log
def greet(name):
    """Return a greeting."""
    return f"Hello, {name}"

print(greet.__name__)  # greet (not 'wrapper')
print(greet.__doc__)   # Return a greeting.

@functools.lru_cache

Memoizes function results using a Least Recently Used cache with a configurable maxsize (default 128). Supports optional parentheses since Python 3.8:

from functools import lru_cache

@lru_cache(maxsize=256)
def fibonacci(n):
    if n < 2:
        return n
    return fibonacci(n - 1) + fibonacci(n - 2)

print(fibonacci(100))
print(fibonacci.cache_info())
# CacheInfo(hits=98, misses=101, maxsize=256, currsize=101)

@functools.cache

Added in Python 3.9. An unbounded version of @lru_cache with no size limit and no LRU eviction. Equivalent to @lru_cache(maxsize=None) but slightly faster because it skips the eviction bookkeeping:

from functools import cache

@cache
def factorial(n):
    return n * factorial(n - 1) if n else 1

print(factorial(10))  # 3628800

@functools.cached_property

Added in Python 3.8. A property that is computed once and cached as an instance attribute. Subsequent reads return the cached value without re-executing the method. The cache can be cleared by deleting the attribute:

from functools import cached_property

class DataSet:
    def __init__(self, values):
        self._values = values

    @cached_property
    def stats(self):
        print("Computing stats...")
        return {
            "mean": sum(self._values) / len(self._values),
            "count": len(self._values),
        }

ds = DataSet([10, 20, 30])
print(ds.stats)  # Computing stats... {'mean': 20.0, 'count': 3}
print(ds.stats)  # {'mean': 20.0, 'count': 3}  (no recomputation)

@functools.singledispatch

Added in Python 3.4. Turns a function into a generic function that dispatches on the type of its first argument. Use .register to define type-specific implementations:

from functools import singledispatch

@singledispatch
def serialize(obj):
    raise TypeError(f"Cannot serialize {type(obj)}")

@serialize.register(int)
def _(obj):
    return str(obj)

@serialize.register(list)
def _(obj):
    return "[" + ", ".join(serialize(item) for item in obj) + "]"

print(serialize(42))         # 42
print(serialize([1, 2, 3]))  # [1, 2, 3]

@functools.singledispatchmethod

Added in Python 3.8. The method-compatible version of @singledispatch. Dispatches on the type of the first argument after self or cls:

from functools import singledispatchmethod

class Formatter:
    @singledispatchmethod
    def format(self, arg):
        return str(arg)

    @format.register
    def _(self, arg: int):
        return f"{arg:,}"

    @format.register
    def _(self, arg: float):
        return f"{arg:.2f}"

f = Formatter()
print(f.format(1000000))  # 1,000,000
print(f.format(3.14159))  # 3.14

@functools.total_ordering

Class decorator that generates missing comparison methods from a minimal set. You define __eq__ and one of __lt__, __le__, __gt__, or __ge__; the decorator fills in the rest:

from functools import total_ordering

@total_ordering
class Version:
    def __init__(self, major, minor):
        self.major = major
        self.minor = minor

    def __eq__(self, other):
        return (self.major, self.minor) == (other.major, other.minor)

    def __lt__(self, other):
        return (self.major, self.minor) < (other.major, other.minor)

v1, v2 = Version(1, 2), Version(2, 0)
print(v1 < v2)   # True
print(v1 >= v2)   # False (auto-generated)

dataclasses Decorators

@dataclasses.dataclass

Class decorator that auto-generates __init__, __repr__, __eq__, and optionally __hash__, __lt__, and others based on class annotations. Supports optional parentheses:

from dataclasses import dataclass

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

p = Point(3.0, 4.0)
print(p)            # Point(x=3.0, y=4.0)
print(p == Point(3.0, 4.0))  # True

contextlib Decorators

@contextlib.contextmanager

Converts a generator function into a context manager. Code before yield runs on entry; code after yield runs on exit:

from contextlib import contextmanager
import time

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

with timer("sort"):
    sorted(range(1_000_000, 0, -1))

@contextlib.asynccontextmanager

Added in Python 3.7. The async version of @contextmanager for use with async with statements:

from contextlib import asynccontextmanager

@asynccontextmanager
async def managed_connection(url):
    conn = await connect(url)
    try:
        yield conn
    finally:
        await conn.close()

abc Decorators

@abc.abstractmethod

Marks a method as abstract, requiring subclasses to provide an implementation before they can be instantiated. Can be stacked with @classmethod, @staticmethod, or @property (always as the innermost decorator):

from abc import ABC, abstractmethod

class Shape(ABC):
    @abstractmethod
    def area(self):
        ...

    @classmethod
    @abstractmethod
    def from_string(cls, s):
        ...

class Circle(Shape):
    def __init__(self, radius):
        self.radius = radius

    def area(self):
        return 3.14159 * self.radius ** 2

    @classmethod
    def from_string(cls, s):
        return cls(float(s))

c = Circle.from_string("5")
print(c.area())  # 78.53975

typing Decorators

Decorators in the typing module are primarily consumed by type checkers and have minimal or no runtime effect.

@typing.overload

Declares multiple type signatures for a single function. The overloaded signatures are for type checkers only; the actual implementation follows without the @overload decorator:

from typing import overload

@overload
def process(data: str) -> str: ...
@overload
def process(data: int) -> int: ...

def process(data):
    if isinstance(data, str):
        return data.upper()
    return data * 2

print(process("hello"))  # HELLO
print(process(5))        # 10

@typing.final

Added in Python 3.8. Signals to type checkers that a method cannot be overridden or a class cannot be subclassed:

from typing import final

class Base:
    @final
    def critical_method(self):
        return "do not override"

# Type checker error: Cannot override final method
# class Child(Base):
#     def critical_method(self):
#         return "overridden"

@typing.override

Added in Python 3.12. Marks a method as intentionally overriding a parent method. Type checkers will flag it as an error if the parent does not define that method, catching typos in method names:

from typing import override

class Animal:
    def speak(self):
        return "..."

class Dog(Animal):
    @override
    def speak(self):
        return "Woof"

    # Type checker error: no 'spek' in parent
    # @override
    # def spek(self):
    #     return "typo"

@typing.runtime_checkable

Added in Python 3.8. Makes a Protocol class usable with isinstance() checks at runtime:

from typing import Protocol, runtime_checkable

@runtime_checkable
class Closable(Protocol):
    def close(self) -> None: ...

class Connection:
    def close(self):
        print("closed")

conn = Connection()
print(isinstance(conn, Closable))  # True

@typing.no_type_check

Disables type checking for a function or class. Annotations on the decorated function or class will not be evaluated by type checkers:

from typing import no_type_check

@no_type_check
def legacy_function(x, y):
    # Type checker ignores this entirely
    return x + y

@typing.dataclass_transform

Added in Python 3.11. Signals to type checkers that a decorator, base class, or metaclass provides dataclass-like behavior. Used by libraries like attrs, pydantic, and SQLAlchemy to get type checker support without using @dataclass directly:

from typing import dataclass_transform

@dataclass_transform()
def my_dataclass(cls):
    # Library implementation that synthesizes __init__, __eq__, etc.
    ...
    return cls

Quick Reference Table

Decorator Module Added Purpose
@propertybuiltins2.2Managed attribute with getter/setter/deleter
@staticmethodbuiltins2.2Method with no implicit first argument
@classmethodbuiltins2.2Method receiving class as first argument
@wrapsfunctools2.5Preserve wrapped function metadata
@lru_cachefunctools3.2Memoization with LRU eviction
@total_orderingfunctools3.2Auto-generate comparison methods
@singledispatchfunctools3.4Type-based function overloading
@cached_propertyfunctools3.8Lazily computed cached attribute
@singledispatchmethodfunctools3.8Type-based method overloading
@cachefunctools3.9Unbounded memoization
@dataclassdataclasses3.7Auto-generate class boilerplate
@contextmanagercontextlib2.5Generator-based context manager
@asynccontextmanagercontextlib3.7Async generator context manager
@abstractmethodabc2.6Require subclass implementation
@overloadtyping3.5Multiple type signatures (type checker only)
@finaltyping3.8Prevent override/subclass (type checker only)
@runtime_checkabletyping3.8Enable isinstance() on Protocol
@no_type_checktyping3.5Disable type checking
@dataclass_transformtyping3.11Signal dataclass-like behavior
@overridetyping3.12Mark intentional method override
Pro Tip

Python 3.13 added @warnings.deprecated (PEP 702) for marking functions, methods, and classes as deprecated with a runtime warning and type-checker support. If you are targeting Python 3.12 or earlier, the same decorator is available via the typing_extensions package.

  1. The three builtins -- @property, @staticmethod, @classmethod -- are the foundation. They are implemented as descriptors and require no imports. Understanding how they customize attribute access through __get__ is the key to understanding how all Python decorators interact with classes.
  2. functools is the decorator powerhouse. It provides caching (@cache, @lru_cache, @cached_property), dispatch (@singledispatch, @singledispatchmethod), comparison generation (@total_ordering), and the essential @wraps for building your own decorators correctly.
  3. The typing decorators are for static analysis, not runtime behavior. @overload, @final, @override, and @dataclass_transform have minimal or no runtime effect. They exist to give type checkers (mypy, pyright) the information needed to validate your code statically.
  4. Always apply @abstractmethod as the innermost decorator when stacking. The abc module documentation specifies this explicitly. When combining with @classmethod, @staticmethod, or @property, the order is: @classmethod (outer), then @abstractmethod (inner).

This reference covers every decorator shipped with CPython's standard library as of Python 3.14. Third-party libraries add their own decorators (Flask's @app.route, pytest's @pytest.fixture, Django's @login_required), but those are built on the same mechanism described throughout this series. The standard library decorators are the toolkit you should know before reaching for any external dependency.