Декоратори в Python
Декоратори є дуже потужним і корисним інструментом у Python, оскільки він дозволяє програмістам змінювати поведінку функції чи класу. Декоратори дозволяють нам обернути іншу функцію, щоб розширити поведінку загорнутої функції, не змінюючи її постійно. Але перш ніж заглибитися в декоратори, давайте розберемося з деякими поняттями, які стануть у нагоді під час вивчення декораторів.
Об'єкти першого класу
У Python функції є першокласні об'єкти це означає, що функції в Python можна використовувати або передавати як аргументи.
Властивості функцій першого класу:
- Функція є екземпляром типу Object.
- Ви можете зберегти функцію в змінній.
- Ви можете передати функцію як параметр іншій функції.
- Ви можете повернути функцію з функції.
- Ви можете зберігати їх у структурах даних, таких як хеш-таблиці, списки тощо.
Для кращого розуміння розгляньте наведені нижче приклади.
приклад 1: Трактування функцій як об’єктів.
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'> ))> |
Вихід:
HELLO HELLO
У наведеному вище прикладі ми призначили функцію shout змінній. Це не призведе до виклику функції, замість цього він бере об’єкт функції, на який посилається shout, і створює друге ім’я, що вказує на нього, yell.
приклад 2: Передача функції як аргументу
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)> |
Вихід:
HI, I AM CREATED BY A FUNCTION PASSED AS AN ARGUMENT. hi, i am created by a function passed as an argument.
У наведеному вище прикладі функція greet приймає іншу функцію як параметр (у цьому випадку крик і шепіт). Функція, передана як аргумент, викликається всередині функції greet.
приклад 3: Повернення функцій з іншої функції.
Python3
# 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> ))> |
Вихід:
25
У наведеному вище прикладі ми створили функцію всередині іншої функції, а потім повернули функцію, створену всередині.
Наведені вище три приклади описують важливі поняття, необхідні для розуміння декораторів. Ознайомившись з ними, давайте тепер заглибимося в декоратори.
Декоратори
Як зазначено вище, декоратори використовуються для зміни поведінки функції або класу. У декораторах функції беруться як аргумент в іншу функцію, а потім викликаються всередині функції-огортки.
Синтаксис для декоратора:
@gfg_decorator def hello_decorator(): print('Gfg') '''Above code is equivalent to - def hello_decorator(): print('Gfg') hello_decorator = gfg_decorator(hello_decorator)''' У наведеному вище коді gfg_decorator є викликаною функцією, яка додасть деякий код поверх іншої викликаної функції, функції hello_decorator, і поверне функцію-огортку.
Декоратор може змінити поведінка :
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()> |
Вихід:
Hello, this is before function execution This is inside the function !! This is after function execution
Давайте подивимося на поведінку наведеного вище коду та як він виконується крок за кроком, коли викликається function_to_be_used.
Давайте перейдемо до іншого прикладу, де ми можемо легко дізнатися час виконання функції за допомогою декоратора.
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> )> |
Вихід:
3628800 Total time taken in : factorial 2.0061802864074707
Що робити, якщо функція щось повертає або їй передається аргумент?
У всіх наведених вище прикладах функції нічого не повернули, тому проблеми не було, але може знадобитися повернуте значення.
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))> |
Вихід:
before Execution Inside the function after Execution Sum = 3
У наведеному вище прикладі ви можете помітити значну різницю в параметрах внутрішньої функції. Внутрішня функція приймає аргумент як *args і **kwargs, що означає, що можна передати кортеж позиційних аргументів або словник ключових аргументів будь-якої довжини. Це робить його загальним декоратором, який може прикрасити функцію, що має будь-яку кількість аргументів.
Ланцюгові декоратори
Простіше кажучи, ланцюжок декораторів означає декорування функції кількома декораторами.
приклад:
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())> |
Вихід:
400 200
Наведений вище приклад схожий на виклик функції як –
decor1(decor(num)) decor(decor1(num2))