logo

Decoratori in Python

Decoratori sono uno strumento molto potente e utile in Python poiché consente ai programmatori di modificare il comportamento di una funzione o classe. I decoratori ci consentono di avvolgere un'altra funzione per estendere il comportamento della funzione avvolta, senza modificarla in modo permanente. Ma prima di addentrarci nel mondo dei decoratori, cerchiamo di comprendere alcuni concetti che ci torneranno utili per imparare a lavorare sui decoratori.

Oggetti di prima classe
In Python, le funzioni sono oggetti di prima classe il che significa che le funzioni in Python possono essere usate o passate come argomenti.
Proprietà delle funzioni di prima classe:

  • Una funzione è un'istanza del tipo Oggetto.
  • È possibile memorizzare la funzione in una variabile.
  • È possibile passare la funzione come parametro a un'altra funzione.
  • È possibile restituire la funzione da una funzione.
  • Puoi memorizzarli in strutture dati come tabelle hash, elenchi, ...

Considera gli esempi seguenti per una migliore comprensione.



Esempio 1: Trattare le funzioni come oggetti.

Python3








# Python program to illustrate functions> # can be treated as objects> def> shout(text):> >return> text.upper()> print>(shout(>'Hello'>))> yell>=> shout> print>(yell(>'Hello'>))>

>

>

Produzione:

HELLO HELLO>

Nell'esempio precedente abbiamo assegnato la funzione Shout a una variabile. Questo non chiamerà la funzione, ma prenderà l'oggetto funzione a cui fa riferimento un grido e creerà un secondo nome che punta ad esso, urla.

Esempio 2: Passando la funzione come argomento

Python3




# Python program to illustrate functions> # can be passed as arguments to other functions> def> shout(text):> >return> text.upper()> def> whisper(text):> >return> text.lower()> def> greet(func):> ># storing the function in a variable> >greeting>=> func(>'''Hi, I am created by a function passed as an argument.'''>)> >print> (greeting)> greet(shout)> greet(whisper)>

>

>

Produzione:

HI, I AM CREATED BY A FUNCTION PASSED AS AN ARGUMENT. hi, i am created by a function passed as an argument.>

Nell'esempio sopra, la funzione di saluto accetta un'altra funzione come parametro (urla e sussurra in questo caso). La funzione passata come argomento viene quindi richiamata all'interno della funzione greet.

Esempio 3: Restituzione di funzioni da un'altra funzione.

Python3




decodifica javascript base64
# Python program to illustrate functions> # Functions can return another function> def> create_adder(x):> >def> adder(y):> >return> x>+>y> >return> adder> add_15>=> create_adder(>15>)> print>(add_15(>10>))>

>

>

Produzione:

25>

Nell'esempio precedente, abbiamo creato una funzione all'interno di un'altra funzione e quindi abbiamo restituito la funzione creata all'interno.
I tre esempi precedenti descrivono i concetti importanti necessari per comprendere i decoratori. Dopo averli esaminati, approfondiamo ora i decoratori.

Decoratori

Come affermato sopra, i decoratori vengono utilizzati per modificare il comportamento della funzione o della classe. In Decorators, le funzioni vengono prese come argomento in un'altra funzione e quindi chiamate all'interno della funzione wrapper.

Sintassi per Decoratore:

@gfg_decorator def hello_decorator(): print('Gfg') '''Above code is equivalent to - def hello_decorator(): print('Gfg') hello_decorator = gfg_decorator(hello_decorator)'''>

Nel codice sopra, gfg_decorator è una funzione richiamabile, che aggiungerà del codice sopra un'altra funzione richiamabile, la funzione hello_decorator e restituirà la funzione wrapper.

Il decoratore può modificare il file comportamento :

Python3




# defining a decorator> def> hello_decorator(func):> ># inner1 is a Wrapper function in> ># which the argument is called> > ># inner function can access the outer local> ># functions like in this case 'func'> >def> inner1():> >print>(>'Hello, this is before function execution'>)> ># calling the actual function now> ># inside the wrapper function.> >func()> >print>(>'This is after function execution'>)> > >return> inner1> # defining a function, to be called inside wrapper> def> function_to_be_used():> >print>(>'This is inside the function !!'>)> # passing 'function_to_be_used' inside the> # decorator to control its behaviour> function_to_be_used>=> hello_decorator(function_to_be_used)> # calling the function> function_to_be_used()>

>

>

Produzione:

Hello, this is before function execution This is inside the function !! This is after function execution>

Vediamo il comportamento del codice precedente e come viene eseguito passo dopo passo quando viene chiamata la funzione function_to_be_used.

Passiamo a un altro esempio in cui possiamo scoprirlo facilmente il tempo di esecuzione di una funzione utilizzando un decoratore.

Python3




# importing libraries> import> time> import> math> # decorator to calculate duration> # taken by any function.> def> calculate_time(func):> > ># added arguments inside the inner1,> ># if function takes any arguments,> ># can be added like this.> >def> inner1(>*>args,>*>*>kwargs):> ># storing time before function execution> >begin>=> time.time()> > >func(>*>args,>*>*>kwargs)> ># storing time after function execution> >end>=> time.time()> >print>(>'Total time taken in : '>, func.__name__, end>-> begin)> >return> inner1> # this can be added to any function present,> # in this case to calculate a factorial> @calculate_time> def> factorial(num):> ># sleep 2 seconds because it takes very less time> ># so that you can see the actual difference> >time.sleep(>2>)> >print>(math.factorial(num))> # calling the function.> factorial(>10>)>

>

>

Produzione:

3628800 Total time taken in : factorial 2.0061802864074707>

Cosa succede se una funzione restituisce qualcosa o viene passato un argomento alla funzione?

In tutti gli esempi precedenti le funzioni non hanno restituito nulla, quindi non si è verificato un problema, ma potrebbe essere necessario il valore restituito.

Python3




def> hello_decorator(func):> >def> inner1(>*>args,>*>*>kwargs):> > >print>(>'before Execution'>)> > ># getting the returned value> >returned_value>=> func(>*>args,>*>*>kwargs)> >print>(>'after Execution'>)> > ># returning the value to the original frame> >return> returned_value> > >return> inner1> # adding decorator to the function> @hello_decorator> def> sum_two_numbers(a, b):> >print>(>'Inside the function'>)> >return> a>+> b> a, b>=> 1>,>2> # getting the value through return of the function> print>(>'Sum ='>, sum_two_numbers(a, b))>

>

>

Produzione:

before Execution Inside the function after Execution Sum = 3>

Nell'esempio sopra, potresti notare una netta differenza nei parametri della funzione interna. La funzione interna accetta l'argomento come *args e **kwargs, il che significa che è possibile passare una tupla di argomenti posizionali o un dizionario di argomenti di parole chiave di qualsiasi lunghezza. Ciò lo rende un decoratore generale in grado di decorare una funzione con un numero qualsiasi di argomenti.

Decoratori incatenati

In termini più semplici, concatenare i decoratori significa decorare una funzione con più decoratori.

Esempio:

Python3




ordinamento delle bolle nell'algoritmo
# code for testing decorator chaining> def> decor1(func):> >def> inner():> >x>=> func()> >return> x>*> x> >return> inner> def> decor(func):> >def> inner():> >x>=> func()> >return> 2> *> x> >return> inner> @decor1> @decor> def> num():> >return> 10> @decor> @decor1> def> num2():> >return> 10> > print>(num())> print>(num2())>

>

>

Produzione:

400 200>

L'esempio precedente è simile alla chiamata della funzione come –

decor1(decor(num)) decor(decor1(num2))>