How to Write a Python Decorator with functools.wraps

Create a decorator that wraps a function while preserving its metadata using functools.wraps.

Easy Python 3.9+ Aug 9, 2026 Functions & basics 12 views 0 copies

Python code

21 lines
Python 3.9+
from functools import wraps


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


@logger
def greet(name):
    """Return a friendly greeting."""
    return f"Hello, {name}!"


if __name__ == "__main__":
    print(greet("Alice"))
    print(f"Function name: {greet.__name__}")
    print(f"Docstring: {greet.__doc__}")

Output

stdout
Calling greet
Hello, Alice!
Function name: greet
Docstring: Return a friendly greeting.

How it works

The @wraps(func) decorator copies the original function's __name__, __doc__, and other metadata onto the wrapper function. This is crucial for debugging and for tools like Sphinx or pytest that rely on function signatures and docstrings. Without @wraps, the wrapper would show up as wrapper instead of greet, and its docstring would be None. The *args, **kwargs signature allows the wrapper to accept any arguments, ensuring that the decorated function works with any call signature.

Common mistakes

  • Forgetting to use `@wraps(func)` and losing the original function's metadata.
  • Not returning `func(*args, **kwargs)` from the wrapper, causing the original function's return value to be lost.
  • Assuming the wrapper needs to handle specific argument names, when using `*args, **kwargs` is more flexible.

Variations

  1. Use `functools.wraps` with a decorator factory to accept arguments, e.g., `@logger(level='info')`.
  2. Apply `@wraps` inside a class-based decorator to preserve metadata on the `__call__` method.

Real-world use cases

  • Logging function calls with timing or parameters in a production service, keeping the original function name in logs.
  • Adding caching or memoization to functions while preserving their signatures for type checkers and documentation.
  • Creating access-control decorators that raise authorization errors but preserve the original function's introspection.

Sponsored

Run this sample

Open the browser IDE to tweak the example and see results without installing anything.

Open editor

More from Functions & basics

Related tutorials and quizzes for this topic.