logo

Dekoratory w Pythonie

Dekoratorzy są bardzo potężnym i użytecznym narzędziem w Pythonie, ponieważ pozwalają programistom modyfikować zachowanie funkcji lub klasy. Dekoratory pozwalają nam owijać inną funkcję w celu rozszerzenia zachowania opakowanej funkcji, bez jej trwałego modyfikowania. Zanim jednak zagłębimy się w dekoratory, przyjrzyjmy się kilku koncepcjom, które przydadzą się w nauce dekoratorów.

Obiekty pierwszej klasy
W Pythonie funkcje są obiekty pierwszej klasy co oznacza, że ​​funkcji w Pythonie można używać lub przekazywać jako argumenty.
Własności funkcji pierwszej klasy:

  • Funkcja jest instancją typu Object.
  • Funkcję można zapisać w zmiennej.
  • Funkcję można przekazać jako parametr do innej funkcji.
  • Możesz zwrócić funkcję z funkcji.
  • Możesz przechowywać je w strukturach danych, takich jak tabele mieszające, listy,…

Aby lepiej zrozumieć, rozważ poniższe przykłady.



Przykład 1: Traktowanie funkcji obiektowo.

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

>

>

Wyjście:

HELLO HELLO>

W powyższym przykładzie przypisaliśmy funkcję krzyk do zmiennej. To nie wywoła funkcji, zamiast tego pobiera obiekt funkcji, do którego odwołuje się krzyk, i tworzy drugą nazwę wskazującą na niego, krzyk.

Przykład 2: Przekazanie funkcji jako argumentu

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

>

>

Wyjście:

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

W powyższym przykładzie funkcja powitania przyjmuje jako parametr inną funkcję (w tym przypadku krzyk i szept). Funkcja przekazana jako argument jest następnie wywoływana wewnątrz funkcji greet.

Przykład 3: Zwracanie funkcji z innej funkcji.

Python3




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

>

>

Wyjście:

25>

W powyższym przykładzie utworzyliśmy funkcję wewnątrz innej funkcji, a następnie zwróciliśmy funkcję utworzoną wewnątrz.
Powyższe trzy przykłady przedstawiają ważne pojęcia potrzebne do zrozumienia dekoratorów. Po ich przejrzeniu zagłębmy się teraz w dekoratory.

Dekoratorzy

Jak wspomniano powyżej, dekoratory służą do modyfikowania zachowania funkcji lub klasy. W dekoratorach funkcje są przyjmowane jako argumenty innej funkcji, a następnie wywoływane wewnątrz funkcji opakowującej.

Składnia dekoratora:

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

W powyższym kodzie gfg_decorator jest funkcją wywoływalną, która doda trochę kodu na wierzch innej wywoływalnej funkcji, funkcji hello_decorator i zwróci funkcję opakowania.

Dekorator może modyfikować plik zachowanie :

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

>

>

Wyjście:

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

Przyjrzyjmy się zachowaniu powyższego kodu i jego działaniu krok po kroku po wywołaniu funkcjifunction_to_be_used.

Przejdźmy do innego przykładu, w którym łatwo się o tym przekonamy czas wykonania funkcji za pomocą dekoratora.

Python3

menu ustawień Androida




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

>

>

Wyjście:

3628800 Total time taken in : factorial 2.0061802864074707>

Co się stanie, jeśli funkcja zwróci coś lub zostanie do niej przekazany argument?

We wszystkich powyższych przykładach funkcje nic nie zwróciły, więc nie było problemu, ale zwrócona wartość może być potrzebna.

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

>

>

Wyjście:

before Execution Inside the function after Execution Sum = 3>

W powyższym przykładzie można zauważyć wyraźną różnicę w parametrach funkcji wewnętrznej. Funkcja wewnętrzna przyjmuje argumenty jako *args i **kwargs, co oznacza, że ​​można przekazać krotkę argumentów pozycyjnych lub słownik argumentów słów kluczowych o dowolnej długości. To sprawia, że ​​jest to ogólny dekorator, który może ozdobić funkcję posiadającą dowolną liczbę argumentów.

Dekoratorzy łańcuszków

Mówiąc prościej, łączenie dekoratorów oznacza dekorowanie funkcji wieloma dekoratorami.

Przykład:

Python3




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

>

>

Wyjście:

400 200>

Powyższy przykład jest podobny do wywołania funkcji jako –

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