Decorator python

Я не понимаю работу декораторов, что происходит когда внутри декоратора вызываем декорируемую функцияю а если не вызывать? Что если, когда это делать при много декораторов, объясните их работу пожалуйста


Ответы (1 шт):

Автор решения: vitidev

Я понимаю это так.

Когда файл выполняется (при import тоже происходит выполнение импортируемого модуля), то по результату выполнения в пространстве имен появляются разные функции, классы и так далее. В зависимости от нужных нам условий (например win/linux) мы можем конструировать нужные нам классы и функции.

Все эти def/class - специальные конструкции для создания "на лету" объектов функций и классов - и для этого вызываются внутренние механизмы для построения этих сущностей (в случае классов это встроенная функция type()).

И вот если встречается декоратор, то при конструировании объекта функции или класса (не путать с экземплярами) дополнительно вызывается функция декоратора, которой передается декорируемая функция/класс и с ними можно что-то сделать.

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

Например:

def my_decorator(func):
    class Foo:
        def run(self):
            print('i am class foo')
    return Foo


@my_decorator
def hello():
    print("hello!")

obj = hello()
obj.run()

Тут мы принимаем декорируемую функцию hello, игнорируем ее и конструируем класс.

А можем в декораторе сделать даже return 1 и у нас вместо функции hello будет определена переменная hello типа int со значенем 1

То есть декораторы являются возможностью вмешаться в механизм конструирования объекта и выполнить любые нужные нам действия.

Например, если мы пишем свой webapi, то можем сделать декоратор @route('/api'), который не будет ничего оборачивать, а зарегистрирует функцию в роутере, а если свой orm, то создаем маппинг для модели. А декоратор abstractmethod всего лишь добавляет к функции аттрибут funcobj.__isabstractmethod__ = True и ничего более.

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

def my_decorator(func):
    return "a"

def my_decorator2(func):
    return 1

@my_decorator
@my_decorator2
def hello():
    print("hello!")

Первым будет вызван my_decorator2 и получит как параметр функцию hello, а вторым будет вызван my_decorator и получит как параметр int (то, что вернула функция my_decorator2)

update: Подправил пост. Все-таки хоть декораторы и метаклассы по смыслу похожи, но декоратор получает уже сконструированный объект функции или класса, а метаклассы заменяют сам процесс создания.

→ Ссылка