Уроки Питон №15/19. Декораторы функций (@simple_decore) в Питон

Урок 19. Декораторы функций в Python

Этот урок посвящен теме декораторов в Python. Большое внимание уделено свойствам функций в Python, на базе которых реализована идея декораторов. Рассмотрены декораторы принимающие аргументы и возвращающие значение из функции.

Что нужно знать о функциях в Python?

Для начала разберем два аспекта связанные с функциями в Python. Во-первых: функция – это объект специального вида, поэтому ее можно передавать в качестве аргумента другим функциям. Во-вторых: внутри функций можно создавать другие функции, вызывать их и возвращать как результат через return. Остановимся на этих моментах более подробно.

Функция как объект

В Python передача одной функции в качестве аргумента другой функции – это нормальная практика. Например, если у вас есть список целых чисел, и вы хотите на базе него получить другой список, элементами которого будут квадраты первого, то такую задачу можно решить в одну строчку.

>>> # исходный список

>>> a = [1, 2, 3, 4, 5]

>>> # функция, возводящая переданное ей число в квадрат

>>> sq = lambda x: x**2

>>> # проверим ее работу

>>> print(sq(5))

25

>>> # получаем список квадратов

>>> b = list(map(sq, a))

>>> print(b)

[1, 4, 9, 16, 25]

Здесь мы передали функции map в качестве первого аргумента функцию sq, которая будет применяться по очереди ко всем элементам списка a.

В Python функция – это специальный объект, который имеет метод __call__(). Если мы создадим вот такой класс.

class DemoCall():

def __call__(self):

return "Hello!"

То объект такого класса можно вызывать как функцию.

>>> hello = DemoCall()

>>> hello()

'Hello!'

Функция внутри функции

Вторым важным свойством функции, для понимания темы декораторов, является то, что их можно создавать, вызывать и возвращать из других функций. На этом построена идея замыкания (closures).

Например, создадим функцию, которая умножает два числа.

def mul(a):

def helper(b):

return a * b

return helper

В ней реализованы два важных свойства которые нам понадобятся: внутри функции mul() создается еще одна функция, которая называется helper(); функция mul() возвращает функцию helper как результат работы.

Вызывается эта функция так:

>>>mul(4)(2)

8

Ее главная фишка состоит в том, что можно создавать на базе функции mul() свои кастомизированные функции. Например, создадим функцию “умножение на три”.

>>>three_mul = mul(3)

>>>three_mul(5)

15

Как вы можете видеть, мы построили функцию three_mul, которая умножает на три любое переданное ей число.

Что такое декоратор функции в Python?

Конструктивно декоратор в Python представляет собой некоторую функцию, аргументом которой является другая функция. Декоратор предназначен для добавления дополнительного функционала к данной функции без изменения содержимого последней.

Создание декоратора

Предположим у нас есть пара простых функций, вот они:

def first_test():

print("Test function 1")

def second_test():

print("Test function 2")

Мы хотим дополнить их так, чтобы перед вызовом основного кода функции печаталась строка “Run function”, а по окончании – “Stop function”.

Сделать это можно двумя способами. Первый – это добавить указанные строки в начало в конец каждой функции, но это не очень удобно, т.к. если мы захотим убрать это, нам придется снова модифицировать тело функции. А если они написаны не нами, либо являются частью общей кодовой базы проекта, сделать это будет уже не так просто. Второй вариант – это воспользоваться знаниями из раздела “Что нужно знать о функциях в Python?”

Создадим вот такую функцию.

def simple_decore(fn):

def wrapper():

print("Run function")

fn()

print("Stop function")

return wrapper

Обернем наши функции в эту оболочку.

first_test_wrapped = simple_decore(first_test)

second_test_wrapped = simple_decore(second_test)

Функции first_test и second_test остались неизменными.

>>> first_test()

Test function 1

>>> second_test()

Test function 2

Функции first_test_wrapped и second_test_wrapped  обладают функционалом, которого мы добивались.

>>> first_test_wrapped()

Run function

Test function 1

Stop function

>>> first_test_wrapped()

Run function

Test function 1

Stop function

Если необходимо, чтобы так работали функций с именами first_test и second_test, то  можно сделать так.

first_test = first_test_wrapped

second_test = second_test_wrapped

Проверим это.

>>> first_test()

Run function

Test function 1

Stop function

>>> second_test()

Run function

Test function 2

Stop function

То, что мы только что сделали и является реализацией идеи декоратора. Но вместо строк:

def first_test():

print("Test function 1")

first_test_wrapped = simple_decore(first_test)

first_test = first_test_wrapped

Можно написать вот так:

@simple_decore

def first_test():

print("Test function 1")

@simple_decore – это и есть декоратор функции.

Передача аргументов в функцию через декоратор

Если функция в своей работе требует наличие аргумента, то его можно передать через декоратор. Создадим декоратор, который принимает аргумент и выводит информацию о декорируемой функции и ее аргументе.

def param_transfer(fn):

def wrapper(arg):

print("Run function: " + str(fn.__name__) + "(), with param: " + str(arg))

fn(arg)

return wrapper

Для демонстрации ее работы создадим функцию, которая выводит квадратный корень переданного ей числа, в качестве декоратора, укажем только что созданный param_transfer.

@param_transfer

def print_sqrt(num):

print(num**0.5)

Выполним эту функцию с аргументом 4.

>>> print_sqrt(4)

Run function: print_sqrt(), with param: 4

2.0

Декораторы для методов класса

Методы классов также можно объявлять с декоратором. Модифицируем декоратор param_transfer.

def method_decor(fn):

def wrapper(self):

print("Run method: " + str(fn.__name__))

fn(self)

return wrapper

Создадим класс для представления двумерного вектора (из математики). В этом классе определим метод norm(), который выводит модуль вектора.

class Vector():

def __init__(self, px = 0, py = 0):

self.px = px

self.py = py

@method_decor

def norm(self):

print((self.px**2 + self.py**2)**0.5)

Продемонстрируем работу этого метода.

>>> vc = Vector(px=10, py=5)

>>> vc.norm()

Run method: norm

11.180339887498949

Возврат результата работы функции через декоратор

Довольно часто, создаваемые функции возвращают какое-либо значение. Для того, чтобы его можно было возвращать через декоратор необходимо соответствующим образом построить внутреннюю функцию.

def decor_with_return(fn):

def wrapper(*args, **kwargs):

print("Run method: " + str(fn.__name__))

return fn(*args, **kwargs)

return wrapper

Этот декоратор можно использовать для оборачивания функций, которые принимают различные аргументы и возвращают значение.

@decor_with_return

def calc_sqrt(val):

return val**0.5

Выполним функцию calc_sqrt с параметром 16.

>>> tmp = calc_sqrt(16)

Run method: calc_sqrt

>>> print(tmp)

4.0

Профессиональный репетитор по математике, информатике и физике:

 

Александр Анатольевич Борцов 


КАК ВЫБРАТЬ:
связаться с Александром Анатольевичем
с помощью WhatsApp (лучше) или Telegram
+7-926-859-12-55 

Когда еще учился в аспирантуре, c самого истока своего продвижения по службе, я мечтал собрать вместе  мои основные интересы научной деятельности в области Квантовой физики и лазеров: Математику, Информатику, Физику и Обучение.

Компетентный математик и физик для студентов и школьников, кандидат физико математических наук, доктор технических наук по специальности радиофизика. Образование: Физический факультет МГУ им.М.В.Ломоносова с отличием, Специальность -Физика. Преподавал в  МЭИ, педагогический стаж более 15 лет. Является автором  монографии на английском языке "Laser Opto-Electronic Oscillator", 2020, изд. Springer. Автор более 60 ти научных публикаций в зарубежных и отечественных научных журналах по темам Квантовая Электроника, Квантовая радиофизика, Лазеры, Наноэлектроника, Лазерный оптоэлектронный генератор и др.. Хорошо   подготовит контрольной работе по математике и физике в 9 класс с помощью интересных схем по развитию памяти. Помогает в написании работ:курсовых.

 Обучал основам Python, MathLab, Data Science и Machine Learning. 

Более 320 учащихся  поступили «на бюджет» в университеты и  ВУЗы Москвы: МГТУ, МЭИ, МАИ и  и т.д.Опыт преподавателя по математике для студентов более 20 лет.Занятия проводятся дистанционно по Skype и Zoom|и очно в Москве м. Китай-город]. Есть большой опыт подготовки к экзаменам по физике и математике по англоязычным программам университетов (SAT,GMAT). По методикам и учебникам университетов готовил к экзаменам по математике и физике  студентов из Канады, Германии, Испании и  Нидерланды. Говорю по английски, владею английским, преподаю на английском математику и физику..
Занятия ведутся Дистанционно по Skype и Zoom и и очно в Москве м. Китай-город

Запись на занятия

Ваше сообщение отправлено