Decorator Internals — What @ Actually Does
A function that takes a function and returns a function — that's all
@my_decorator
def greet():
return 'hello'
# Above is identical to:
greet = my_decorator(greet)
@ isn't magic. It's syntactic convenience for applying a function that takes a function and returns a new function.
Basic Structure
wrapper is a closure capturing the outer function's variable (func). *args, **kwargs ensures the wrapper accepts any signature.
Why functools.wraps
Without it, greet.__name__ becomes 'wrapper'. Original metadata (name, docstring, signature) lost. @functools.wraps(func) copies original metadata.
Decorators with Arguments
Triple nesting. repeat(3) returns decorator, decorator(say_hello) returns wrapper. FastAPI's @app.get('/path') uses this pattern.
Key Points
@decorator is syntactic sugar for func = decorator(func)
wrapper function captures original func as closure
functools.wraps(func) essential to preserve original metadata
Decorators with args use triple nesting: outer(args) → decorator(func) → wrapper(*args)