Python Decorators Explained: From @property to Retry Logic in 15 minutes (2026)
Dekorátory sú funkciou, ktorá oddeľuje „pozná Python“ od „plyne číta Python“. Vyzerajú magicky, ale sú mechanické: @decorator na funkcii je presne f = decorator(f). To je všetko. Všetko ostatné v tomto návode je, že jedna čiara je aplikovaná v rôznych tvaroch.
Teória jedného riadku
Keď píšeš:
Python ho transformuje na:
To je celý mechanik. @decorator_name nad def spúšťa def_name = dekorator_name(def_name) po definícii. Ak si to osvojíte, dekoratéri prestanú byť navždy tajomní.
Písanie svojho prvého dekoratéra (60 sekúnd)
Dekorátor je akýkoľvek volateľný prvok, ktorý preberá funkciu a vracia funkciu. Typický tvar:
„args, *kwargs“ v obale je obranný vzor – umožňuje dekoratérovi pracovať na akejkoľvek funkcii bez ohľadu na podpis. Preskočte to a dostanete TypeError: wrapper() má 0 pozičných argumentov, ale boli dané 2 v momente, keď niekto ozdobí funkciu parametrami.
Oprava @functools.wraps
Jedna jemná chyba: po zdobení je „add.__name__“ „zabaliť“, nie „pridať“. Docstring a tipy na typ tiež zmiznú. Oprava je jeden import:
Pravidlo: každý dekoratér, ktorý napíšete, by mal používať `@functools.wraps(fn)`. Stojí to jeden riadok a zabraňuje celej kategórii bolesti pri ladení (introspekcia, zariadenia pytest, formátovače protokolovania, pickle – všetky sa bez toho potichu prerušia).
Štyri dekorátory, ktoré uvidíte v každej kódovej základni
1. @vlastnosť — vypočítané atribúty
@vlastnosť robí metódu volateľnou ako keby to bol atribút. Ideálne pre hodnoty odvodené len na čítanie. Pre cestu zápisu existuje aj @area.setter, ale 90 % použití @property je len na čítanie.
2. @staticmethod a @classmethod
@classmethod dostane cls (samotnú triedu) a používa sa pre alternatívne konštruktory. @staticmethod neprináša nič zvláštne a je to obyčajná funkcia, ktorá náhodou žije v priestore názvov triedy.
3. @functools.cache — zapamätanie
Jeden z najvýkonnejších dekoratérov stdlib. Automaticky zapamätá funkciu na základe jej argumentov. Vyžaduje, aby všetky argumenty boli hašovateľné (žiadne zoznamy / diktáty ako argumenty – použite n-tice).
4. @dataclasses.dataclass — eliminácia štandardných modelov
@dataclass číta anotácie typu na úrovni triedy a automaticky generuje __init__, __repr__, __eq__ a (s frozen=True) __hash__. Je to najväčšie zlepšenie kvality života v Pythone 3.7+.
Písanie dekorátora „@retry“ (reálny príklad)
Dekoratér, ktorý pri zlyhaní zopakuje funkciu s exponenciálnym stiahnutím:
Všimnite si tri vnorené funkcie: retry akceptuje konfiguračné argumenty a vráti decorator; decorator prijme funkciu a vráti wrapper; wrapper spustí cyklus opakovania. Tento trojvrstvový vzor vyzerá ako každý dekoratér s argumentmi – zapamätajte si tvar, nie konkrétny príklad.
Dekoratéri podľa triedy (zriedkavé, ale užitočné)
Dekoratér je ľubovoľný. Triedy s __call__ fungujú tiež:
Použite, keď dekorátor potrebuje udržať stav, ktorý prežije jeden hovor (počítadlo, vyrovnávacia pamäť, vedro s limitom sadzby).
Bežné nástrahy
1. Zabudnutie na `@functools.wraps` — introspekcia sa ticho preruší.
2. Premenlivé predvolené argumenty v samotnom dekorátore – aj tu sa objavila klasická chyba def wrapper(x, cache=[]).
3. Zdobenie metód bez akceptovania `ja` — pamätajte, že ja je len pozičný argument; *args, **kwargs to chytí dobre.
4. Pri ukladaní na seba záleží: @a\n@b\ndef f() je f = a(b(f)). Čítať zásobníky zdola nahor.
Cvičte
Napíšte dekorátor @timing, ktorý vypíše, ako dlho trvá spustenie zabalenej funkcie, a potom ho aplikujte na funkciu, ktorá vypočíta sum(rozsah(10_000_000)). Celý dekoratér má 8 riadkov s functools.wraps + time.perf_counter.
Keď si osvojíte, že @x je f = x(f), dekorátory sa stanú jednou z najproduktívnejších funkcií Pythonu. Sú všade v skutočných kódových základniach: cesty Flask/FastAPI (@app.route), zariadenia pytestu (@pytest.fixture), zobrazenia Django (@požadované_prihlásenie), validátory Pydantic (@field_validator). Naučiť sa ich písať sami odomkne schopnosť čítať každý z nich.
Ďalší krok: [10 praktických lekcií pre dekoratérov] (/kurzy/senior) — vytvorte si @retry, @memoise, @rate_limit a @requires_auth od začiatku so skutočným Pythonom spusteným vo vašom prehliadači.