DEV Community

Kai Thorne
Kai Thorne

Posted on

5 Python functools Decorators That Actually Saved My Codebase

When I started maintaining a legacy Python codebase, the hardest part wasn't understanding the business logic — it was reading the same 50-line pattern scattered across 12 modules.

Then I discovered functools — not just lru_cache, but the deeper tools that change how you structure code.

1. @singledispatch

Replace isinstance chains with clean type dispatch:

from functools import singledispatch

@singledispatch
def format_data(data):
    return str(data)

@format_data.register(dict)
def _(data):
    return json.dumps(data, indent=2)

@format_data.register(list)
def _(data):
    return '\n'.join(str(x) for x in data)
Enter fullscreen mode Exit fullscreen mode

2. @total_ordering

Define __eq__ and one comparison, get all six for free:

from functools import total_ordering

@total_ordering
class Priority:
    def __init__(self, level):
        self.level = level

    def __eq__(self, other):
        return self.level == other.level

    def __lt__(self, other):
        return self.level < other.level

assert Priority(3) >= Priority(2)
assert Priority(1) <= Priority(2)
Enter fullscreen mode Exit fullscreen mode

3. @wraps

Never lose __name__ or __doc__ in your decorators:

from functools import wraps

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

@log_call
def process_payment(amount):
    """Process a payment transaction."""
    return f"Processed ${amount}"

print(process_payment.__name__)  # 'process_payment'
print(process_payment.__doc__)   # 'Process a payment transaction.'
Enter fullscreen mode Exit fullscreen mode

4. @lru_cache

Use cache_info() to monitor your memoization:

from functools import lru_cache
import time

@lru_cache(maxsize=128)
def fetch_user_permissions(user_id):
    time.sleep(1)  # Simulate DB
    return {"can_read": True, "can_write": False}

print(fetch_user_permissions.cache_info())
# CacheInfo(hits=0, misses=1, maxsize=128, currsize=1)
Enter fullscreen mode Exit fullscreen mode

5. partial

Replace one-off factory classes with a single call:

from functools import partial

def create_api_client(base_url, api_key, timeout=30, retries=3):
    return {"base_url": base_url, "key": api_key[-4:], "timeout": timeout}

prod_client = partial(create_api_client, "https://api.prod.com", timeout=60)
dev_client = partial(create_api_client, "https://api.dev.local", timeout=5)
Enter fullscreen mode Exit fullscreen mode

I've been collecting these patterns into reference templates. The Prompt Creator Bundle — Developer Edition includes prompt templates for generating Python code with these patterns applied correctly.

Top comments (0)