ProgrammingBackend Developer

Explain how decorators work in Python. What are their main benefits, how are they implemented, and what nuances can arise when they are used?

Pass interviews with Hintsage AI assistant

Answer

Decorators are functions that take another function as an argument and return a new function with extended or modified behavior. They are commonly used for logging, permission checks, caching, execution time, and more.

Decorators are implemented using closures or classes that implement the __call__ method. The classic syntax is:

# Simple decorator def simple_decorator(func): def wrapper(*args, **kwargs): print("Before calling the function") result = func(*args, **kwargs) print("After calling the function") return result return wrapper @simple_decorator def my_func(): print("Main function") my_func()

As a result, it executes like this:

Before calling the function
Main function
After calling the function

The main benefit is the encapsulation of repetitive logic outside the main business logic.

Nuances:

  • Without using functools.wraps, the original function's name and its docstring will be lost.
  • If a decorator takes arguments, it requires triple nesting of functions.

Trick Question

Question: "If I decorate a function with a decorator and then try to get the function's name via __name__, what will I see and how can I preserve the original name?"

Answer:

By default, the name changes to the name of the wrapper (usually wrapper). To preserve the original metadata, use functools.wraps:

import functools def dec(f): @functools.wraps(f) def wrapper(*args): return f(*args) return wrapper @dec def foo(): pass print(foo.__name__) # will output 'foo', not 'wrapper'

Examples of real errors due to lack of knowledge of the nuances of the topic


Story

In a large resource automation project, after wrapping functions with decorators, the system of automated tests using reflection on test function names broke. The problem was the absence of functools.wraps.


Story

A logging decorator did not support functions with different signatures because *args, **kwargs were not used. Some functions simply failed with Silent Fail.


Story

In a project with authorization in the REST API, a developer implemented a decorator with parameters, but forgot to nest the functions correctly (there was double nesting instead of three). As a result, the decorator could not accept parameters.