Advanced decorators: stacking, parameters, and @property
Once you understand the basic decorator pattern, three extensions show up everywhere.
Stacking is the first. When you write @bracket_a above @bracket_b above def f(), Python applies them bottom-up: f = bracket_a(bracket_b(f)). The bottom decorator wraps the function first; the top decorator wraps that result. Read the stack from bottom to top to trace what happens to f. In Pydantic, @field_validator('name') sits above @classmethod — the classmethod decorator fires first (making the method receive cls), then field_validator registers it.
Parametrized decorators are the second. @repeat(3) looks like a decorator with an argument, but what is really happening is that repeat(3) is called first and must return a decorator. So you need three nested functions: the outer one receives the parameter (n), the middle one receives the function (fn), and the inner one is the actual wrapper. This three-level nesting confuses everyone the first time, but once you see that repeat(3) returns a normal decorator, the pattern clicks.
@property is the third — a built-in decorator that turns a method into an attribute-like accessor. obj.radius looks like reading a field but actually calls a function. The companion @radius.setter does the same for assignment, and that is where you guard invariants: if value <= 0: raise ValueError(...). Properties make the class interface clean while keeping validation logic centralized.
Functools docs: [1], descriptor how-to (property): [2].
Sources
Tasks
Card Info
- Topic: Data Science Praktikum
- Difficulty: Intermediate
- Completed: 0 users