Изучаем Декораторы в Python

автор

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

Простая функция

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

Все что мы сделали в этом коде, это вызвали функцию и указали значение выдачи. Давайте создадим другую функцию:

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

Давайте взглянем на полную версию данного кода:

Так и работает декоратор. Мы создали одну функцию и передали её другой второй функции. Вторая функция является функцией декоратора. Декоратор модифицирует или усиливает функцию, которая была передана и возвращает модификацию. Если вы запустите этот код, вы увидите следующий выход в stdout:

Давайте немного изменим код, чтобы превратить another_function в декоратор:

Обратите внимание на то, что декоратор начинается с символа @, за которым следует название функции, которую мы собираемся «декорировать». Для получения декоратора python, вам нужно только разместить его в строке перед определением функции. Теперь, когда мы вызываем **a_function, она будет декорирована, и мы получим следующий результат:

Давайте создадим декоратор, который будет делать что-нибудь полезное.

Создание логируемого декоратора

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

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

Встроенные декораторы

Python содержит несколько встроенных декораторов. Из всех этих декораторов, самой важной троицей являются:

  • @classmethod
  • @staticmethod
  • @property

Также существуют декораторы в различных разделах стандартной библиотеки Python. Одним из примеров является functools.wraps. Мы сосредоточимся на трех главных декораторах, указанных выше.

@classmethod и @staticmethod

Я не пользовался ими ранее, так что сделал небольшое исследование.

  • Декоратор <*@classmethod>* может быть вызван при помощи экземпляра класса, или напрямую, через собственный класс Python в качестве первого аргумента. В соответствии с документацией Python: он может быть вызван как в классе (например, C.f()), или в экземпляре (например, C().f()). Экземпляр игнорируется, за исключением его класса. Если метод класса вызван для выведенного класса, то объект выведенного класса передается в качестве подразумеваемого первого аргумента.
  • Декоратор @classmethod, в первую очередь, используется как чередуемый конструктор или вспомогательный метод для инициализации.
  • Декоратор <*@staticmethod>* — это просто функция внутри класса. Вы можете вызывать их обоих как с инициализацией класса так и без создания экземпляра класса. Обычно это применяется в тех случаях, когда у вас есть функция, которая, по вашему убеждению, имеет связь с классом. По большей части, это выбор стиля.

Если мы взглянем на пример кода, в котором показано, как работает декоратор, это может помочь понять основные принципы:

Этот пример демонстрирует, что вы можете вызывать обычный метод и оба метода декоратора одним и тем же путем. Обратите внимание на то, что вы можете вызывать обе функции @classmethod и @staticmethod прямо из класса или из экземпляра класса. Если вы попытаетесь вызвать обычную функцию при помощи класса (другими словами, DecoratorTest.doubler(2)), вы получите ошибку TypeError. Также стоит обратить внимание на то, что последний оператор вывода показывает, что decor.static_quad возвращает обычную функцию вместо связанного метода.

Свойства Python (@property)

Python содержит очень удобный небольшой концепт, под названием property, который выполняет несколько полезных задач. Мы рассмотрим, как делать следующее:

  • Конвертация метода класс в атрибуты только для чтения;
  • Как реализовать сеттеры и геттеры в атрибут

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

Дешевые просмотры Вконтакте с гарантиями Вы найдете на сервисе https://doctorsmm.com/. Помимо приятного прайса, здесь Вы сможете получить персональные условия для работы с полученным ресурсом. Так, например, Вы сможете подобрать скорость поступления страниц таким образом, чтобы она соответствовала статистике Вашего сообщества или профиля. Соответственно, Вы получаете выгодное и действительно безопасное предложение. А еще на сайте постоянно действуют крупные оптовые скидки — торопитесь сделать заказ!

Для других это было очень кстати при написании методов конверсии, которые нужно было принять в качестве методов. Давайте взглянем на простой пример:

В данном коде мы создали два класса атрибута, или свойств: self.first_name и self.last_name.
Далее мы создали метод full_name, который содержит декоратор <*@property>*. Это позволяет нам использовать следующий код в сессии интерпретатора:

Как вы видите, в результате превращение метода в свойство, мы можем получить к нему доступ при помощи обычной точечной нотации. Однако, если мы попытаемся настроить свойство на что-то другое, мы получим ошибку AttributeError. Единственный способ изменить свойство full_name, это сделать это косвенно:

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

Замена сеттеров и геттеров на свойство Python

Давайте представим, что у нас есть код, который написал кто-то, кто не очень понимает Python. Как и я, вы скорее всего, видели такого рода код ранее:

Для использования этого класса, нам нужно использовать сеттеры и геттеры, которые определены как:

Если вам нужно добавить обычную точечную нотацию атрибутов в данный код без выведения из строя всех приложений в этой части кода, вы можете сделать это очень просто, добавив свойство:

Мы добавили одну строк в конце этого кода. Теперь мы можем делать что-то вроде этого:

Как мы видим, когда мы используем свойство таким образом, это позволяет свойству fee настраивать и получать значение без поломки наследуемого кода. Давайте перепишем этот код с использованием декоратора property, и посмотрим, можем ли мы получить его для разрешения установки.

Данный код демонстрирует, как создать сеттер для свойства fee. Вы можете делать это, декорируя второй метод, который также называется fee с декоратором, под названием <@fee.setter>. Сеттер будет вызван, когда вы сделаете что-то вроде следующего:

Если вы взгляните на подписи под свойством, то это будут fget, fset, fdel и doc в качестве аргументов. Вы можете создать другой декорируемый метод, используя то же название связи с функцией delet при помощи <@fee.deleter*>*, если вы хотите поймать команду **del для атрибута.

Подведем итоги

С этого момента вы должны понимать, как создавать собственные декораторы и как использовать встроенные декораторы Python. Мы рассмотрели classmethod, @property и @staticmethod. Надеюсь, вы будете использовать встроенные декораторы, и создавать свои собственные.

Вам может быть интересно

Scroll Up