Huzi Blogs
BlogCategories
BlogCategories
Disclaimer & Data Privacy Policy
Project by huzi.pk

© 2026 blogs.huzi.pk. All Rights Reserved.

    Back to all posts
    Python

    Mastering Python Decorators: A Practical Guide (2026)

    By Huzi

    Every FastAPI route begins with an @ line, and so does every Pydantic model and pytest fixture. Decorators are not exotic Python trivia — they are the grammar of the modern ecosystem. Understand them once, properly, and half of your favourite framework's documentation stops being mysterious.

    The anatomy: a function that returns a wrapper

    A decorator is just a function that takes a function and returns a new one that does a little extra work around it.

    from functools import wraps
    
    def log_calls(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            print(f"Calling {func.__name__}")
            result = func(*args, **kwargs)
            return result
        return wrapper
    
    @log_calls
    def say_hello(name: str) -> str:
        """Greet someone by name."""
        return f"Hello, {name}!"
    

    The @wraps(func) line is not decoration for its own sake: without it, the wrapped function loses its name, docstring and signature, which quietly breaks documentation tools and IDE introspection. Copy it every time, no exceptions.

    Factories: decorators that take arguments

    The pattern that confuses everyone — a decorator with parameters — is one more layer: a function that returns a decorator.

    from functools import wraps
    
    def require_role(role: str):
        def decorator(func):
            @wraps(func)
            def wrapper(user, *args, **kwargs):
                if role not in user.roles:
                    raise PermissionError(f"Requires role: {role}")
                return func(user, *args, **kwargs)
            return wrapper
        return decorator
    

    That is the entire trick behind @app.get("/hello") and @retry(times=3). Once you see the extra layer as just another function call, the panic stops.

    Do not hand-roll what the stdlib ships

    For caching, functools.cache handles the unbounded case and functools.lru_cache(maxsize=128) bounds it — a memoised fibonacci runs instantly with two lines. For retries with exponential backoff against a flaky API, tenacity is more robust than anything you will write in an afternoon. Write your own decorators for the things specific to your codebase — audit logging, permission checks, timing — and use the batteries for the generic jobs.

    Typing them properly

    Untyped decorators erase signatures from the type checker's view. The modern fix is ParamSpec, and it is what the large libraries do internally:

    from typing import Callable, ParamSpec, TypeVar
    from functools import wraps
    
    P = ParamSpec("P")
    R = TypeVar("R")
    
    def log_calls(func: Callable[P, R]) -> Callable[P, R]:
        @wraps(func)
        def wrapper(*args: P.args, **kwargs: P.kwargs) -> R:
            return func(*args, **kwargs)
        return wrapper
    

    This keeps full autocompletion alive through the wrapper — the difference between a decorator your team enjoys and one they quietly delete.

    When not to write one

    A decorator should earn its layer. If the wrapper adds nothing a plain function call could, skip it — flat beats nested applies to decorators most of all. The best decorator is the one a reader forgets is there.

    Layers that protect quietly, without taking credit — the idea follows you out of the editor. In Gaza, neighbours and paramedics wrap the injured in whatever cloth survives the night and keep working: the oldest protection layer there is, running on no framework at all. May theirs hold, and may the day come when it never has to.

    When your head is full of wrappers, the cure is a place with none. We run the weekend escapes out of Sialkot for exactly this at HTG Travels — Swat and Kalam itineraries with drivers who know the road and hotels confirmed in writing before you leave. The mountains do not care about your stack trace; that is their entire medical value.

    Advertisements


    You Might Also Like

    Digital Print 90/70 Lawn Suit 3-Pc with Diamond Voil Dupatta (Unstitched)

    Digital Print 90/70 Lawn Suit 3-Pc with Diamond Voil Dupatta (Unstitched)

    PKR 3600

    Luxury Heavy Schiffli Embroidered Lawn Suit 3-Pc | Embroidered Organza Dupatta

    Luxury Heavy Schiffli Embroidered Lawn Suit 3-Pc | Embroidered Organza Dupatta

    PKR 6650

    Formal Heavy Embroidered Organza Mehndi Suit 2026 | Plain Trouser

    Formal Heavy Embroidered Organza Mehndi Suit 2026 | Plain Trouser

    PKR 5100

    Luxurious Handwork Heavy Embroidered Organza Bridal Suit 2025 | Dyed Satin Silk Trouser

    Luxurious Handwork Heavy Embroidered Organza Bridal Suit 2025 | Dyed Satin Silk Trouser

    PKR 9600

    Heavy Embroidered Velvet Party Wear Suit 2026 | Emb. Organza Dupatta & Silk Trouser

    Heavy Embroidered Velvet Party Wear Suit 2026 | Emb. Organza Dupatta & Silk Trouser

    PKR 8700

    Advertisements


    Related Posts

    Python
    The Serpent's Grace: The Ultimate Python 3.13 Guide (2026)
    The practice-path way to learn Python: a project ladder from a script that saves you an hour to a deployed AI agent, plus the 2026 tooling — uv, ruff, pyright, pytest — that keeps the climb sane.

    By Huzi

    Read More
    Python
    Getting Started with Python 3.13 for Absolute Beginners (2026)
    The strict quickstart: install Python 3.13 properly (including the Windows PATH trap), write and run your first script today, and know exactly what to learn in what order next.

    By Huzi

    Read More
    Python
    Introduction to Python 3.13: The All-Purpose Language (2026)
    What Python actually is: an interpreted, whitespace-sensitive language whose readable syntax now runs everything from Sunday scripts to the AI stack, with 3.13's speed work humming under the hood.

    By Huzi

    Read More
    Python
    Automate the Boring Stuff with Python: 5 Modern Scripts (2026)
    Three of the five scripts worth keeping: a pathlib file organizer, an async httpx scraper, and a bulk image resizer with Pillow — real code, modern Python 3.13, tested shapes.

    By Huzi

    Read More
    Programming
    A Beginner's Guide to React Hooks: Mastering Modern React (2026)
    useState, useEffect, the React 19 form hooks, and the two rules that keep hooks from breaking — each with a runnable snippet.

    By Huzi

    Read More
    Programming
    Python Testing Pyramid 2026: The Complete Problem-Solving Guide
    The 70/20/10 pyramid in practice — pytest fixtures and parametrize, boundary mocking, Hypothesis, testcontainers, and the CI loop your team can actually trust.

    By Huzi

    Read More