Sari la conținutul principal
Python intermediar2026-07-29 · 10 min de citit

Decoratori Python explicați: de la @property la reîncercați logica în 15 minute (2026)

Decoratorii sunt caracteristica care separă „cunoaște Python” de „citește Python fluent”. Par magice, dar sunt mecanice: @decorator pe o funcție este exact f = decorator(f). Asta este. Orice altceva din acest tutorial este acea linie aplicată în diferite forme.

Teoria cu o singură linie

Cand scrii:

▶ PYTHONeditable · runs in your browser

Python îl transformă în:

▶ PYTHONeditable · runs in your browser

Acesta este totul mecanic. @decorator_name deasupra unui def rulează def_name = decorator_name(def_name) după definiție. Dacă interiorizezi acest lucru, decoratorii încetează să mai fie misterioși pentru totdeauna.

Scrierea primului tău decorator (60 de secunde)

Un decorator este orice apelabil care preia o funcție și returnează o funcție. Forma tipică:

▶ PYTHONeditable · runs in your browser

*args, **kwargs din wrapper este un model defensiv - permite decoratorului să lucreze la orice funcție, indiferent de semnătură. Omiteți-l și veți obține TypeError: wrapper() acceptă 0 argumente poziționale, dar s-au dat 2 în momentul în care cineva decorează o funcție cu parametri.

Remedierea @functools.wraps

Un bug subtil: după decorare, add.__name__ este "wrapper", nu "add". Docstrings și indicii de tip dispar de asemenea. Remedierea este un singur import:

▶ PYTHONeditable · runs in your browser

Regula: fiecare decorator pe care îl scrieți ar trebui să folosească `@functools.wraps(fn)`. Costă o linie și previne o întreagă categorie de dureri de depanare (introspecție, dispozitive pytest, formatare logging, pickle — toate se întrerup fără ea).

Cei patru decoratori pe care îi veți vedea în fiecare bază de cod

1. @property — atribute calculate

▶ PYTHONeditable · runs in your browser

@property face o metodă apelabilă ca și cum ar fi un atribut. Perfect pentru valori derivate numai pentru citire. Există, de asemenea, @area.setter pentru calea de scriere, dar 90% din utilizările @property sunt doar pentru citire.

2. @staticmethod și @classmethod

▶ PYTHONeditable · runs in your browser

@classmethod primește cls (clasa însăși) și este folosit pentru constructori alternativi. @staticmethod nu primește nimic special și este o funcție simplă care se întâmplă să trăiască în spațiul de nume al clasei.

3. @functools.cache — memorare

▶ PYTHONeditable · runs in your browser

Unul dintre cei mai puternici decoratori stdlib. Memorează automat funcția pe baza argumentelor sale. Necesită ca toate argumentele să fie hashable (fără liste/dicte ca argumente - utilizați tupluri).

4. @dataclasses.dataclass — eliminarea boilerplate

▶ PYTHONeditable · runs in your browser

@dataclass citește adnotările de tip la nivel de clasă și generează automat __init__, __repr__, __eq__ și (cu frozen=True) __hash__. Este cea mai mare îmbunătățire a calității vieții din Python 3.7+.

Scrierea unui decorator @retry (exemplu real)

Un decorator care reîncearcă o funcție la eșec cu backoff exponențial:

▶ PYTHONeditable · runs in your browser

Observați cele trei funcții imbricate: retry acceptă argumentele de configurare și returnează decorator; decorator acceptă funcția și returnează wrapper; wrapper rulează bucla de reîncercare. Acest model cu trei straturi este așa cum arată orice decorator cu argumente - memorați forma, nu exemplul specific.

Decoratori bazați pe clasă (rari, dar utili)

Un decorator este orice apelabil. Cursurile cu __call__ funcționează și ele:

▶ PYTHONeditable · runs in your browser

Utilizați atunci când decoratorul trebuie să păstreze starea care supraviețuiește unui singur apel (un contor, un cache, o găleată cu limită de rată).

Capcane comune

1. Uitând `@functools.wraps` — introspecția se întrerupe în tăcere.

2. Argumente implicite modificabile în decoratorul însuși — clasicul def wrapper(x, cache=[]) mușcă și aici.

3. Metode de decorare fără a accepta `self` — amintiți-vă că self este doar un argument pozițional; *args, **kwargs prinde bine.

4. Comandarea contează la stivuire: @a\n@b\ndef f() este f = a(b(f)). Citiți stivele de jos în sus.

Practică

Scrieți un decorator @timing care imprimă cât timp durează funcționarea funcției înfășurate, apoi aplicați-l unei funcții care calculează sum(range(10_000_000)). Întregul decorator este de 8 linii cu functools.wraps + time.perf_counter.


Odată ce interiorizați că @x este f = x(f), decoratorii devin una dintre cele mai productive caracteristici ale lui Python. Sunt peste tot în baze de cod reale: rute Flask/FastAPI (@app.route), fixtures pytest (@pytest.fixture), vizualizări Django (@login_required), validatoare Pydantic (@field_validator). Dacă înveți să le scrii singur, deblochează capacitatea de a citi pe fiecare dintre acestea.

Următorul pas: 10 lecții practice de decorator — construiți „@retry”, „@memoise”, „@rate_limit” și „@requires_auth” de la zero cu Python real rulând în browser.

Ești gata să-l încerci?

15 lecții gratuite după o înscriere gratuită — fără card. Eșantionați platforma, apoi decideți.

Începe gratuit →

Or unlock every lesson

Pro — $12/mo, unlimited AI, cancel any time. Refund within 14 days worldwide.

See Pro plans →

Get one Python lesson + one career idea every Friday

No spam, no "buy our course now". Three bullets, every Friday. Unsubscribe with one click.