ProgrammingBackend Developer

What are higher-order function decorators in Python, how do they enable the 'wrapping' pattern, and what should be considered when working with function metadata/documentation?

Pass interviews with Hintsage AI assistant

Answer.

In Python, a higher-order function decorator is a function that takes another function (or class) as an argument and returns a new function (or a new modified class). Decorators are often used to implement the "wrapping" pattern, allowing additional logic (such as logging, caching, permission checks, etc.) to be added to existing functions without changing their original code.

To preserve the name, documentation, and other metadata of the original function, it is recommended to use the functools.wraps function:

import functools def log_decorator(func): @functools.wraps(func) def wrapper(*args, **kwargs): print(f'Calling {func.__name__}') return func(*args, **kwargs) return wrapper @log_decorator def add(a, b): """Add two numbers""" return a + b print(add(2, 3)) # Output: Calling add 5 print(add.__name__) # Output: add print(add.__doc__) # Output: Add two numbers

Key point: without functools.wraps, the wrapped function will lose its name, documentation, and other original metadata, which negatively impacts debugging and auto-documentation.

Trick question.

If a function is decorated without using functools.wraps, what will happen to the name and doc attributes of the function?

Answer: They will be inherited from the inner wrapper function (usually 'wrapper'), and you will lose the original metadata.

def simple_decorator(func): def wrapper(*args, **kwargs): return func(*args, **kwargs) return wrapper @simple_decorator def f(): """This is docstring""" pass print(f.__name__) # Output: 'wrapper' (NOT 'f') print(f.__doc__) # Output: None (not 'This is docstring')

Examples of real mistakes due to ignorance of the topic's nuances.


Story

In a project, a complex system of decorators for logging API endpoints was implemented, but functools.wraps was not applied. As a result, auto generation of documentation (Swagger/OpenAPI) and introspection tools displayed the names of all endpoints as 'wrapper', with documentation missing. This significantly complicated support, testing, and maintenance.


Story

When writing unit tests using pytest, there was a failure in test auto-discovery: test functions decorated with their own decorators without wraps were not found because their name was incorrect. The reason is that pytest searches for functions by name.


Story

When tracing exception stack traces, the stack trace always pointed to "wrapper", making it impossible to understand which specific function raised the error, as root metadata was lost due to the absence of functools.wraps in custom decorators.