Рубрики
Без рубрики

Декоратор класса Python – Часть I – простой без аргументов конфигурации.

Краткий рецепт и протокол раскрывают реализацию декоратора на основе класса Python.

Автор оригинала: Dobri Stoilov.

Возможно, вы уже изучили декораторов в своем Python Developer live?! Это быстрый рецепт без большого количества объяснений о внутренних органах, и он может выглядеть как волшебное зелье, которое вы, возможно, не понимаете в данный момент…Не волнуйся! Поверьте мне, любой хороший маг начинает, не зная, как магия работает внутренне, но учится заклинаниям. Наверняка любопытный должен перевернуть землю, чтобы узнать, как она работает!

Отлично! Декораторы на основе классов Python-это два типа декораторов функций, один из которых принимает параметры, а другой-просто нет.

Давайте начнем с простого, без аргументов.

1-й нам нужна целевая функция для обертывания my_function и класс , который будет реализовывать оболочку декоратора для нашей функции MyClassDecorator , давайте закодируем ее:

class MyClassDecorator:
  pass
    
    
@MyClassDecorator
def my_function(*args, **kwargs):
    print('my orginal function')

Мы не ожидаем многого, но давайте запустим его.

$ipython -i class_decorators.py
...
TypeError: MyClassDecorator() takes no arguments

Интерпретатор Python говорит нам, что каким-то образом в этот момент “@” что-то было помещено в конструктор моего класса Decorator (), и наша реализация просто пропустила его, давайте выясним, что передается :

class MyClassDecorator:
    def __init__(self, *args, **kwargs):
        print('__init__', self, args, kwargs)

@MyClassDecorator
def my_function(*args, **kwargs):
    print('my orginal function')

Объекты декоратора класса Python ожидают один аргумент инициализации (плюс самость) . Это должно быть предметом функции для декоратора

__init__ <__main__.MyClassDecorator object at 0x7f0974c25710> (,) {}

И теперь пришло время вызвать my_function() с любыми аргументами и кваргами давайте посмотрим эффект сейчас:

$ipython -i class_decorators.py
...
__init__ <__main__.MyClassDecorator object at 0x7f734beb9748> (,) {}
...
In [1]: my_function(1, 2, 3)
..
TypeError: 'MyClassDecorator' object is not callable

Объекты декоратора класса Python должны быть вызываемыми (реализации вызов метод) , который обернет исходный код функции

давайте определим некоторые общие псевдо цели нашего декоратора:

  • (1) Предварительно обработайте что-то перед исходной функцией my_function
  • (2) Выполните исходный код my_function и получите результат
  • ((3) После обработки результата моей функции и возврата значения после обработки
class MyClassDecorator:
    def __init__(self, func):
        self.func = func
       
    def __call__(self, *args, **kwargs):
        print('preprocessing', args)
        if args:
            if isinstance(args[0], int):
                a = list(args)
                a[0] += 5
                args = tuple(a)
                print('preprocess OK', args) 
        r = self.func(*args, **kwargs)
        print('postprocessing', r)
        r += 7
        return r
        

@MyClassDecorator
def my_function(*args, **kwargs):
    print('call my_function', args, kwargs)
    return 3

В резюме:

Рецепт реализации простого декоратора на основе классов python:

  1. __init__(self, func ) – аргумент func будет ссылаться на функцию, созданную в переменной-члене объекта тела init-функция self.func – он вам понадобится для цели (2).

  2. __call__(self, *args, **kwargs) – который на самом деле является кодом оболочки для вашей оформленной функции, реализуйте цель: (1), (2), (3) в том же порядке.

Далее: декоратор класса python с аргументами