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

Содержание

Примечание. В этой статье мы несколько раз говорили о «возвращаемом объекте», что означает, что возвращаемое значение является объектом. Цель вызова «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: