Python Decorators Explained: From @property to Retry Logic in 15 minutes (2026)
Dekorátoři jsou funkcí, která odděluje „zná Python“ od „čte Python plynule“. Vypadají kouzelně, ale jsou mechanické: @decorator na funkci je přesně f = decorator(f). To je vše. Vše ostatní v tomto tutoriálu spočívá v tom, že jedna čára je aplikována v různých tvarech.
Teorie jednoho řádku
Když píšeš:
Python jej transformuje na:
To je celý mechanik. @decorator_name nad def po definici spustí def_name = decorator_name(def_name). Pokud si to osvojíte, dekoratéři přestanou být navždy tajemní.
Psaní svého prvního dekoratéra (60 sekund)
Dekorátor je jakýkoli callable, který přebírá funkci a vrací funkci. Typický tvar:
„args, *kwargs“ v obalu je obranný vzor – umožňuje dekoratérovi pracovat na jakékoli funkci bez ohledu na podpis. Přeskočte to a dostanete TypeError: wrapper() bere 0 pozičních argumentů, ale byly zadány 2 ve chvíli, kdy někdo ozdobí funkci parametry.
Oprava @functools.wraps
Jedna drobná chyba: po zdobení je add.__name__ "zabalit", nikoli ,,přidat"`. Docstrings a tipy na typ také zmizí. Oprava je jeden import:
Pravidlo: každý dekoratér, který napíšete, by měl používat `@functools.wraps(fn)`. Stojí to jeden řádek a zabraňuje celé kategorii bolesti při ladění (introspekce, zařízení pytest, formátovače protokolování, pickle – vše se bez něj tiše rozbije).
Čtyři dekorátoři, které uvidíte v každé kódové základně
1. @property — vypočítané atributy
@vlastnost způsobí volání metody jako by to byl atribut. Ideální pro hodnoty odvozené pouze pro čtení. Pro cestu zápisu existuje také @area.setter, ale 90 % použití @property je pouze pro čtení.
2. @staticmethod a @classmethod
@classmethod získá cls (samotnou třídu) a používá se pro alternativní konstruktory. @staticmethod nepřináší nic zvláštního a je to obyčejná funkce, která náhodou žije uvnitř jmenného prostoru třídy.
3. @functools.cache — zapamatování
Jeden z nejvýkonnějších dekoratérů stdlib. Automaticky ukládá funkci do paměti na základě jejích argumentů. Vyžaduje, aby všechny argumenty byly hashovatelné (žádné seznamy / diktáty jako argumenty – použijte n-tice).
4. @dataclasses.dataclass — eliminace standardní
@dataclass čte anotace typu na úrovni třídy a automaticky generuje __init__, __repr__, __eq__ a (s frozen=True) __hash__. Je to největší zlepšení kvality života v Pythonu 3.7+.
Psaní dekorátoru @retry (příklad ze skutečného světa)
Dekorátor, který při selhání zopakuje funkci s exponenciálním stažením:
Všimněte si tři vnořených funkcí: retry přijímá konfigurační argumenty a vrací decorator; decorator přijme funkci a vrátí wrapper; wrapper spustí opakovací smyčku. Tento třívrstvý vzor vypadá tak, jak vypadá každý dekoratér s argumenty – zapamatujte si tvar, ne konkrétní příklad.
Třídní dekoratéři (vzácné, ale užitečné)
Dekoratér je libovolný. Třídy s __call__ fungují také:
Použijte, když dekorátor potřebuje udržet stav, který přežije jeden hovor (počítadlo, mezipaměť, bucket s limitem sazby).
Běžná úskalí
1. Zapomenutí `@functools.wraps` — introspekce tiše přestane.
2. Proměnlivé výchozí argumenty v samotném dekorátoru — i zde se objevila klasická chyba def wrapper(x, cache=[]).
3. Zdobení metod bez akceptování `já` — pamatujte, že já je jen poziční argument; *args, **kwargs to chytne dobře.
4. Při skládání záleží na pořadí: @a\n@b\ndef f() je f = a(b(f)). Číst zásobníky zdola nahoru.
Cvičte
Napište dekorátor @timing, který vytiskne, jak dlouho trvá spuštění zabalené funkce, a poté jej aplikujte na funkci, která vypočítá sum(rozsah(10_000_000)). Celý dekorátor má 8 řádků s functools.wraps + time.perf_counter.
Jakmile si osvojíte, že @x je f = x(f), stanou se dekorátory jednou z nejproduktivnějších funkcí Pythonu. Jsou všude ve skutečných kódových základnách: cesty Flask/FastAPI (@app.route), zařízení pytest (@pytest.fixture), zobrazení Django (@požadováno_přihlášení), validátory Pydantic (@field_validator). Naučíte-li se je psát sami, odemknete schopnost číst každý z nich.
Další krok: 10 praktických lekcí dekoratérů — sestavte @retry, @memoise, @rate_limit a @requires_auth od nuly se skutečným Pythonem spuštěným ve vašem prohlížeči.