ProgrammingBackend Developer

What are class decorators in Python? How can they be used to modify or enhance the functionality of classes? Provide an example and discuss possible nuances.

Pass interviews with Hintsage AI assistant

Answer.

A class decorator is a function that takes a class as an argument and returns either a modified or a completely new class. They allow you to dynamically add methods, change the behavior of existing methods, or even return a subclass that extends the functionality of the original class.

Simplest example of a class decorator:

def add_repr(cls): def __repr__(self): return f'<{cls.__name__}: {self.__dict__}>' cls.__repr__ = __repr__ return cls @add_repr class Point: def __init__(self, x, y): self.x = x self.y = y p = Point(3, 4) print(p) # <Point: {'x': 3, 'y': 4}>
  • The add_repr decorator dynamically adds the __repr__ method to all classes it is applied to.

Nuances:

  • Class decorators can return not only modifications to the class, but also completely wrapped (e.g., proxy classes or subclasses).
  • Errors can occur if the decorator does not support the *args and **kwargs arguments used when creating instances of the class.

Trick question.

What happens if two class decorators are applied one after the other? Is the order of their application always obvious?

Answer:

Decorators are applied "from the bottom up": first the decorator directly above the class declaration is applied, then the one above it, and so on. The order is VERY IMPORTANT, as the result of the first decorator is passed into the second, and so on.

@dec1 @dec2 class Test: ... # Equivalently: # Test = dec1(dec2(Test))

Examples of real errors due to lack of knowledge about the subtleties of the topic.


Story

In an e-commerce application, they wanted to log class methods, but inadvertently returned the wrong object from the decorator, causing methods to lose their class properties, which broke inheritance and broke the model's functionality.


Story

In the project for auto-generating new methods, they used an add-on decorator but forgot about super() when returning a subclass. As a result, the hierarchy and MRO were disrupted, leading to non-functional calls to the base class in child classes.


Story

In a data pipeline, they attempted to wrap classes with multiple decorators (logger, change tracker), but due to the incorrect order of application, they encountered method name conflicts, resulting in bugs in production due to "missing" methods.