logo

Decoradors en Python

Decoradors són una eina molt potent i útil en Python, ja que permet als programadors modificar el comportament d'una funció o classe. Els decoradors ens permeten embolicar una altra funció per tal d'ampliar el comportament de la funció embolicada, sense modificar-la permanentment. Però abans d'aprofundir en els decoradors, entenem alguns conceptes que seran útils per aprendre els decoradors.

Objectes de primera classe
A Python, les funcions són objectes de primera classe el que significa que les funcions en Python es poden utilitzar o passar com a arguments.
Propietats de les funcions de primera classe:

  • Una funció és una instància del tipus Object.
  • Podeu emmagatzemar la funció en una variable.
  • Podeu passar la funció com a paràmetre a una altra funció.
  • Podeu tornar la funció des d'una funció.
  • Podeu emmagatzemar-los en estructures de dades com ara taules hash, llistes,...

Considereu els exemples següents per a una millor comprensió.



Exemple 1: Tractar les funcions com a objectes.

Python 3








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

>

>

Sortida:

HELLO HELLO>

A l'exemple anterior, hem assignat la funció shout a una variable. Això no cridarà la funció, sinó que agafa l'objecte de funció al qual fa referència un crit i crea un segon nom que l'assenyala, cridar.

Exemple 2: Passant la funció com a argument

Python 3




# 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)>

>

>

Sortida:

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

A l'exemple anterior, la funció de salutació pren una altra funció com a paràmetre (cridar i xiuxiuejar en aquest cas). A continuació, la funció passat com a argument s'anomena dins de la funció salutació.

Exemple 3: Retorn de funcions d'una altra funció.

Python 3




què és un hashset en java
# 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>))>

>

>

Sortida:

25>

A l'exemple anterior, hem creat una funció dins d'una altra funció i després hem retornat la funció creada dins.
Els tres exemples anteriors mostren els conceptes importants que es necessiten per entendre els decoradors. Després de recórrer-los, endinsem-nos ara en els decoradors.

Decoradors

Com s'ha dit anteriorment, els decoradors s'utilitzen per modificar el comportament de la funció o classe. A Decorators, les funcions es prenen com a argument en una altra funció i després es criden dins de la funció d'embolcall.

Sintaxi per al decorador:

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

Al codi anterior, gfg_decorator és una funció cridable, que afegirà algun codi a la part superior d'una altra funció cridable, la funció hello_decorator i retornarà la funció d'embolcall.

El decorador pot modificar el comportament :

Python 3




# 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()>

>

>

Sortida:

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

Vegem el comportament del codi anterior i com s'executa pas a pas quan es crida la funció_to_be_used.

Anem a un altre exemple on podem esbrinar fàcilment el temps d'execució d'una funció utilitzant un decorador.

Python 3




# 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>)>

>

>

Sortida:

3628800 Total time taken in : factorial 2.0061802864074707>

Què passa si una funció retorna alguna cosa o es passa un argument a la funció?

En tots els exemples anteriors, les funcions no van retornar res, de manera que no hi va haver cap problema, però pot ser que calgui el valor retornat.

Python 3




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))>

java instanciat
>

>

Sortida:

before Execution Inside the function after Execution Sum = 3>

A l'exemple anterior, podeu notar una gran diferència en els paràmetres de la funció interna. La funció interna pren l'argument com a *args i **kwargs, el que significa que es pot passar una tupla d'arguments posicionals o un diccionari d'arguments de paraula clau de qualsevol longitud. Això el converteix en un decorador general que pot decorar una funció amb qualsevol nombre d'arguments.

Encadenant Decoradors

En termes més senzills, encadenar decoradors significa decorar una funció amb múltiples decoradors.

Exemple:

Python 3




# 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())>

>

>

Sortida:

400 200>

L'exemple anterior és similar a cridar la funció com -

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