Skip to content
All Posts

Python Decorators and Descriptors

Implementation-focused notes on Python function and class decorators, descriptor protocols, and common usage patterns.

Decorators

A decorator receives a function or class and returns the object that should replace it. Function decorators are useful for cross-cutting behavior such as timing, logging, caching, permission checks, and registration.

from functools import wraps
def trace(func):
@wraps(func)
def wrapper(*args, **kwargs):
print('calling', func.__name__)
return func(*args, **kwargs)
return wrapper

Use functools.wraps so the wrapper retains the original name, documentation, and related metadata. A decorator that accepts arguments is one more function layer: the outer function receives configuration and returns the actual decorator.

Descriptors

A descriptor is an object that defines __get__, __set__, or __delete__. When stored on a class, it controls attribute access on instances. Functions are descriptors too, which is how retrieving a function from an instance produces a bound method.

Data descriptors define __set__ or __delete__ and take precedence over instance attributes. Non-data descriptors can be shadowed by the instance dictionary. Descriptors are useful for validation, computed properties, lazy values, and reusable attribute behavior; store per-instance values on the instance rather than on the shared descriptor itself.


Originally published on SegmentFault.