Декоратор – это шаблон проектирования в Python, который помогает добавлять дополнительные функции к исходной функции без изменения ее структуры.
В следующей статье я познакомлю вас с декоратором для ты.
Содержание
- Необходимые знания
- Введение в декоратор
- Синтаксическая конфета @
- Передать аргументы в декорированную функцию
- Декоратор с параметрами
- functools.wraps()
Примечание. В этой статье мы несколько раз говорили о «возвращаемом объекте», что означает, что возвращаемое значение является объектом. Цель вызова «return object» — подчеркнуть, что объект также может быть гибким для передачи между функциями.
Необходимые знания
Прежде чем углубиться в Decorator, вы должны сначала узнать два базовых знания о Python:
Первоклассная функция
Функция в Python относится к первоклассным функциям. Это означает, что функции в Python можно рассматривать как переменные. Его можно передать в другие функции в качестве аргумента, а также можно рассматривать как возвращаемый объект, назначенный другим переменным.
Закрытие
Еще одна базовая концепция декоратора связана с замыканием. Закрытие включает в себя два основных элемента:
- Есть функция, которая определяет в нем еще один и возвращает созданный в качестве возвращаемого значения.
- Созданная функция должна ссылаться на локальную переменную в объемлющей функции, которая сама определяет новую функцию.
Эти две основные концепции не являются основной темой этой статьи. Если вам это интересно, я перечисляю два сайта в конце статьи, которые говорят об этом.
Введение декоратора
Давайте просто посмотрим пример:
В этом примере я создаю две функции, teacher()
и student()
. Они будут печатать свои обязанности индивидуально. Если вы хотите проверить время запуска функции, вы можете импортировать модуль time
, чтобы показать, когда они работают. Добавьте коды в определение следующим образом:
Когда другие функции также должны отображать время начала, они также могут добавить те же самые коды в определение. Это настолько неэффективно и делает ваш код избыточным. Если это так, вы можете попробовать использовать декоратор, который поможет вам оптимизировать содержимое:
Как видите, я определил новую функцию show_time
. show_time
импортирует модуль time
для использования его функции. Из-за свойств Closure вложенная функция может получить доступ к локальным переменным включающих функций, даже если включающие функции уже выполнились.
Давайте посмотрим на строку 15, teacher
обрабатывается как аргумент show_time
. В show_time
определенная функция wrap
может получить доступ к объекту func
, а также может использовать функцию, определенную в time
. Затем добавьте print()
в wrap
и выполните func
. На этом создание новой функции, имеющей дополнительные возможности и не меняющей исходную функцию, завершено. В конце show_time
он вернул вновь определенную функцию wrap
в teacher_t
.
В следующий раз, когда мы выполним teacher_t
, мы сможем не только получить вывод teacher()
, но и получить время начала функции без изменения кода в teacher()
. Код в строке 16 делает то же самое, что и строка 15.
Другой метод — присвоить возвращаемый объект исходному объявлению. Например, в строке 19 можно назначить возвращаемый объект show_time
на teacher
. Этот способ является более интуитивным, и дополнительные функции будут работать автоматически при выполнении teacher()
.
Синтаксис Конфеты @
Если вы хотите использовать более одного декоратора, вы можете использовать код, показанный ниже:
В строке 18, как видите, эта строка кода слишком длинная, чтобы определить порядок и имя декоратора. В Python есть синтаксическая конфета @
, которая может помочь вам упростить использование.
Добавление формата @decorator
перед функцией может легко помочь вам распознать декоратор. С помощью @
Вам не нужно добавлять другие коды к содержимому. Просто используйте его как обычно, тогда вы сможете получить расширенную функцию.
Порядок выполнения украшения
Основываясь на выводе, вы можете видеть, что порядок декораторов в приведенных выше кодах сверху вниз: show_time
первый, show_func_name
второй, teacher
последний.
Это показывает, что show_func_name
первым украшает teacher
.
Сначала teacher
передается в show_func_name
для украшения.
Во-вторых, возвращаемый объект show_func_name
, wrap1
, отправляется show_time
. Наконец, последний возвращаемый объект, wrap2
, назначается teacher
.
Как правило, декоратор, ближайший к декорируемой функции, выполняется первым, затем вторым и так далее.
Вот почему вывод сначала показывает местное время, затем имя функции и, наконец, работу с декорированной функцией teacher
. Вы должны обратить на это внимание при использовании.
Передать аргументы в декорированную функцию
В некоторых ситуациях декорированной функции могут потребоваться некоторые переменные в качестве аргументов. вы можете добавить такое же количество аргументов к украшающей функции. Следуйте кодам, например:
Иногда установка определенного количества аргументов для декорирующей функции ограничена, потому что вы не знаете, какая функция будет декорирована при создании декоратора. Возможно, украшенная функция будет иметь пять или более аргументов. В этой ситуации вы можете использовать *args
для получения различного количества позиционных аргументов или использовать **kwargs
для приема аргументов ключевого слова в зависимости от типа вашего аргумента.
Использование*args
и**kwargs
повышает совместимость декоратора. Больше не нужно ограничивать количество аргументов. Декоратор можно использовать шире и шире.
Если вы не знаете использование, показанное выше, вы можете проверить ссылку, чтобы узнать.
Декоратор с параметрами
Эта часть покажет вам, как создать декоратор с параметрами и как он интерпретируется в Python. Давайте посмотрим пример:
Здесь я определяю две функции, одну из которых нужно декорировать, decorated
, а другую — декоратор, show_func_name
. Этот декоратор должен показывать имя декорируемой функции. Если я хочу передать аргумент декоратору, мы не можем просто добавить еще один параметр к определению show_function_name
. Мы должны создать еще одну вложенную функцию, чтобы принять ее.
Синтаксис candy, @
, примет идентификатор объекта для выполнения украшения. Этот объект может быть функцией или идентификатором класса. Когда интерпретатор читает строку 11, он сначала выполнит последнюю часть, decorator_arg('red')
затем запустит декоратор.
В первой части строка 'red'
будет передана в decorator_arg
в качестве параметров. Выполняемая функция определяет новую функцию show_func_name
и отправляет ее @
в качестве возвращаемого объекта. @
рассматривает show_func_name
как декоратор для украшения функции, decorated
.
Когда @
декорирует, он автоматически позволяет первому аргументу декоратора быть объектом, который находится в строке рядом с @
, и управляет декоратором.
Наконец, он назначит возвращаемый объект show_func_name
, wrap
, декорированной функции decorated
.
Помните, что свойство Closure позволяет замкнутой функции получать доступ к локальным переменным внешних функций, даже если они завершили свою работу. После оформления, когда вы вызываете decorated
, он сначала получает доступ к параметру decorator_arg
, color
и печатает его в строке 4, "I wish the...”
, а затем использует параметр func
для доступа к своему атрибуту __name__
. и распечатайте его по строке 5. Наконец, выполните декорированную функцию.
Вот и весь процесс декорирования. Надеюсь, это введение будет вам полезно.
functools.wraps()
При использовании декораторов вы можете столкнуться со следующей проблемой.
Сначала Создание декоратора, show_func_name
, направлено на то, чтобы показать имя декорированной функции, "teacher"
, но на выходе будет “wrap2”
. Почему это вызывает результат? В зависимости от порядка работы декоратора декоратор, ближайший к декорируемой функции, будет выполнен первым. show_time
сначала украсит teacher
, затем его возвращаемое значение, wrap2
, будет украшено show_func_name
. Вот почему func.__name__
в wrap1
это "wrap2"
.
Теперь мы знаем проблему. Как мы можем решить эту проблему? Вы можете использовать стандартный модуль Python — functools
, чтобы победить его. Например :
Как видите, добавление декоратора functools.wraps(func)
до того, как вложенная функция решит проблему. Декоратор wraps()
может сделать вложенную функцию похожей на декорированную, скопировав такие атрибуты, как __name__
, __doc__
и т. д. Если вам это интересно, я дам ссылку, и вы можете проверить это.
Руководство
Поговорите об аргументе в Python:
Разговор о замыканиях Python: