Treci la conținutul principal

Decoratori în Python

Cu un decorator, poți da unei funcții un comportament suplimentar, fără să-i atingi codul.

Un decorator este el însuși o funcție. Primește o funcție ca intrare și returnează una nouă.


Decorator de bază

Mai întâi definește decoratorul, apoi scrie @decorator_name pe rândul de deasupra funcției căreia vrei să-l aplici.

În exemplu, rândul @changecase, aflat chiar deasupra lui myfunction, o „decorează” cu changecase.

Așadar, changecase este decoratorul.

Iar myfunction este funcția care este decorată.

Exemplu

Acest decorator transformă în majuscule orice returnează funcția decorată.

Prompt
Creează un decorator changecase care transformă valoarea returnată de o funcție în majuscule. Aplică-l unei funcții care returnează "Hello Sally" și afișează rezultatul.
Ieșire: program Python complet

Apelarea repetată a unui decorator

Un decorator poate fi refolosit de câte ori vrei. Pune-l pur și simplu deasupra fiecărei funcții care are nevoie de el.

Exemplu

Același decorator @changecase aplicat pe două funcții:

Prompt
Creează un decorator changecase care transformă valorile returnate în majuscule. Aplică-l pe două funcții diferite și afișează ambele rezultate.
Ieșire: program Python complet

Argumente în funcția decorată

Și o funcție care are nevoie de argumente poate fi decorată, atâta timp cât funcția wrapper transmite mai departe acele argumente:

Exemplu

Decorarea unei funcții care primește un argument:

Prompt
Creează un decorator changecase care funcționează cu o funcție ce primește un argument. Funcția decorată trebuie să returneze un salut scris cu majuscule.
Ieșire: program Python complet

*args și **kwargs

Un decorator nu poate ști întotdeauna ce argumente va primi funcția decorată. Soluția este să-i dai funcției wrapper parametrii (*args, **kwargs). Astfel, poate primi orice număr de argumente de orice tip și le poate transmite mai departe funcției decorate.

Exemplu

Funcția wrapper devine sigură cu *args și **kwargs:

Prompt
Creează un decorator changecase care folosește *args și **kwargs pentru flexibilitate. Aplică-l unei funcții care primește un parametru pentru nume.
Ieșire: program Python complet

Decorator cu argumente

Ca să-i dai unui decorator propriile argumente, înfășoară-l într-un nivel suplimentar de funcție.

Exemplu

O fabrică de decoratori: argumentul pe care îl primește decide cu ce fel de litere va fi scris rezultatul.

Prompt
Creează o fabrică de decoratori changecase care primește un argument n. Dacă n==1, transformă rezultatul în litere mici; altfel, transformă-l în majuscule.
Ieșire: program Python complet

Mai mulți decoratori

O funcție poate avea mai mulți decoratori.

Pune pur și simplu apelurile decoratorilor unul peste altul.

Sunt aplicați în ordine inversă, începând cu decoratorul cel mai apropiat de funcție.

Exemplu

Un decorator adaugă un salut, iar celălalt transformă textul în majuscule:

Prompt
Creează doi decoratori: changecase (majuscule) și addgreeting (adaugă un text de salut). Aplică-i pe amândoi, unul peste altul, unei funcții și afișează rezultatul.
Ieșire: program Python complet

Păstrarea metadatelor funcției

Fiecare funcție Python are metadate, pe care le poți citi prin atributele ei __name__ și __doc__.

Când decorezi o funcție însă, acele metadate se pierd, iar valorile originale nu mai sunt disponibile.

Biblioteca standard are o soluție: funcția functools.wraps păstrează numele și docstring-ul funcției originale.

Exemplu

O funcție nedecorată își raportează propriul nume prin __name__:

Prompt
Arată cum poți accesa numele unei funcții folosind atributul __name__.
Ieșire: program Python complet

Exemplu

Întreabă o funcție decorată care îi este numele și răspunsul este diferit:

Prompt
Arată că o funcție decorată își pierde __name__ original. Afișează __name__ al unei funcții decorate.
Ieșire: program Python complet

Exemplu

Cu functools.wraps importat și aplicat, numele și docstring-ul originale se păstrează.

Prompt
Folosește functools.wraps pentru a păstra numele original al funcției la decorare. Afișează __name__ al funcției decorate.
Ieșire: program Python complet