Декораторы — важная часть Python. Простыми словами: это функции, которые изменяют функциональность других функций. Они помогают делать наш код короче и более питоничным. Большинство новичков не знают, где их использовать, поэтому я расскажу о некоторых областях, где декораторы могут сделать ваш код чище. Сначала давайте обсудим, как писать собственные декораторы.
Это, вероятно, одна из самых сложных концепций для освоения. Мы будем обсуждать её шаг за шагом, чтобы вы могли полностью её понять.
Всё является объектом
Сначала давайте разберёмся с функциями в Python:
Определение функций внутри функций
Это были основы функций. Давайте углубим ваши знания. В Python мы можем определять одну функцию внутри другой функции:
Теперь мы знаем, что можно определять другие функции внутри функции. Иными словами, мы можем создавать вложенные функции. Теперь вам нужно узнать ещё немного: функции также могут возвращать функции.
Возврат функций из функций
На самом деле, нет необходимости выполнять другую функцию внутри функции; мы также можем вернуть её как результат:
Посмотрите на этот код ещё раз. В операторе if/else мы возвращаем greet и welcome, а не greet() и welcome(). Почему так? Потому что когда вы ставите пару круглых скобок после неё, функция выполняется; однако если вы не ставите скобки после неё, её можно передавать и присваивать другим переменным, не выполняя. Понимаете? Позвольте объяснить немного подробнее.
Когда мы пишемa = hi(),hi()она выполняется, и поскольку параметр name по умолчанию равен yasoob, функцияgreet()возвращается.
-
Мы также можем вывестиhi()(), что выведет:теперь вы в функции greet()。
-
Если мы изменим инструкцию наa = hi(name = "ali"), тоwelcome()функция будет возвращена.
Передача функции в качестве аргумента другой функции
Теперь у вас есть все необходимые знания, чтобы узнать, что такое декораторы на самом деле. Декораторы позволяют выполнять код до и после функции.
Ваш первый декоратор
В предыдущем примере мы фактически уже создали декоратор! Теперь давайте изменим предыдущий декоратор и напишем немного более полезную программу:
Видите? Мы только что применили принципы, которые изучили ранее. Именно это и делают декораторы в Python! Они оборачивают функцию и так или иначе изменяют её поведение. Теперь вы можете задаться вопросом: в нашем коде мы не использовали символ@? Это просто сокращённый способ создать декорированную функцию. Вот как мы используем@для запуска предыдущего кода:
Надеюсь, теперь у вас есть базовое понимание того, как работают декораторы Python. Есть проблема, если мы запустим следующий код:
print(a_function_requiring_decoration.__name__) # Output: wrapTheFunction
Это не то, что мы хотели! Вывод должен быть "a_function_requiring_decoration". Здесь функция была заменена на warpTheFunction. Она перезаписала имя нашей функции и строку документации. К счастью, Python предоставляет нам простую функцию для решения этой проблемы, а именно functools.wraps. Давайте изменим предыдущий пример, чтобы использовать functools.wraps:
Теперь намного лучше. Далее давайте изучим некоторые распространённые случаи использования декораторов.
Спецификация шаблона:
Примечание:@wrapsОн принимает функцию для декорирования и добавляет возможность копировать имя функции, строку документации, список аргументов и так далее. Это позволяет нам получать доступ к атрибутам функции до декорирования внутри декоратора.
Сценарии использования
Теперь давайте посмотрим, в чём декораторы действительно сильны, и как их использование упрощает управление некоторыми вещами.
Authorization
Декораторы могут помочь проверить, имеет ли кто-то право использовать конечную точку веб-приложения. Они активно используются в веб-фреймворках Flask и Django. Вот пример использования авторизации на основе декораторов:
Логирование
Логирование — ещё одна яркая сторона использования декораторов. Вот пример:
Уверен, вы уже придумываете ещё одно умное применение декораторов.
Декораторы с параметрами
Подумайте об этом: разве @wraps тоже не декоратор? Но он принимает параметр, как и любая обычная функция. Так почему бы и нам не сделать то же самое? Это потому, что когда вы используете синтаксис @my_decorator, вы применяете функцию-обёртку, которая принимает одну функцию в качестве аргумента. Помните, в Python всё является объектом, и это включает функции! Учитывая это, мы можем написать функцию, которая возвращает функцию-обёртку.
Встраивание декораторов в функции
Давайте вернемся к примеру с логированием и создадим функцию-обёртку, которая позволяет указать лог-файл для вывода.
Классы декораторов
Теперь у нас есть декоратор logit, подходящий для продакшена, но когда некоторые части нашего приложения всё ещё хрупкие, исключения могут требовать более срочного внимания. Например, иногда вы просто хотите записать в файл. В других случаях вы хотите отправить проблему, которая привлекла ваше внимание, на электронную почту, а также сохранить запись в журнале. Это сценарий для использования наследования, но до сих пор мы видели только функции, используемые для создания декораторов.
К счастью, классы также можно использовать для создания декораторов. Так что теперь давайте перепишем logit с использованием класса, а не функции.
Эта реализация имеет дополнительное преимущество — она чище, чем подход с вложенной функцией, а обёртывание функции по-прежнему использует тот же синтаксис, что и раньше:
@logit()
def myfunc1():
pass
Теперь давайте создадим подкласс logit, чтобы добавить функциональность электронной почты (хотя тема электронной почты здесь не будет раскрыта).
С этого момента @email_logit будет иметь тот же эффект, что и @logit, но в дополнение к логированию он также будет отправлять электронное письмо администратору.
Адрес оригинальной статьи: https://eastlakeside.gitbooks.io/interpy-zh/content/decorators/