Skip to content
Back to 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.

Copyright notice

Unless otherwise stated, quietin owns the copyright in all articles. All rights reserved. Except as permitted by law or with prior written permission, reproduction or republication, in whole or in part, is prohibited. Permitted quotations must credit the author and link to the original article.