Автор оригинала: Dobri Stoilov.
Здесь мы продолжаем раскрывать протокол о декораторе на основе классов и о том, как он реализован в python3. Вы можете проверить и предыдущую статью: как конструктор классов строит без аргументов В большинстве случаев мы хотели бы передать аргументы нашему декоратору, чтобы настроить вещи, необходимые для упаковки. Сходство с теми, у кого нет аргументов, заключается в том, что нам снова нужны оба метода init и call … но теперь логика немного изменилась, давайте проверим:
class MyClassDecorator: def __init__(self, *a, **kw): print('__init__',a ,kw) def __call__(self, *a, **kw): print('__call__',a, kw) @MyClassDecorator(1,2,3,"decorator configuration") def my_function(*args, **kwargs): print('call my_function', args, kwargs) return 3
Когда мы запускаем скрипт, теперь легко понять, что и куда переместилось…
Python 3.7.0 (default, Jan 29 2019, 14:54:06) Type 'copyright', 'credits' or 'license' for more information IPython 7.2.0 -- An enhanced Interactive Python. Type '?' for help. __init__ (1, 2, 3, 'decorator configuration') {} __call__ (,) {}
Вы видите, как аргументы не передаются одинаково, теперь сначала в нем просто берет то, что необходимо для настройки, в вашу функциональность обертывания, а исходная функция передается в вызов
Мы можем использовать ту же методологию, что и в предыдущей статье, и поставить псевдо-цели, которые будут эмулировать что-то общее о шаблоне декоратора, и это не сильно отличается от предыдущего случая, это просто улучшается с нашей пользовательской (и может быть по умолчанию) конфигурацией и параметризацией, всегда делая вещи гибкими и повторно полезными.
class MyClassDecorator: def __init__(self, *a, **kw): self.conf_args = a self.conf_kw = kw # self.func = None def __call__(self, func): # self.func = func def wrapper(*args, **kwargs): print('preprocessing') print('preprocessing configuration', self.conf_args, self.conf_kw) if args: if isinstance(args[0], int): a = list(args) a[0] += 5 args = tuple(a) print('preprocess OK', args) r = func(*args, **kwargs) print('postprocessing', r) r += 7 return r return wrapper @MyClassDecorator(1001,a='some configuration') def my_function(*args, **kwargs): print('call my_function', args, kwargs) return 3
и попробуйте это в оболочке
In [1]: my_function(1,2,3, a="OK") preprocessing preprocessing configuration (1001,) {'a': 'some configuration'} preprocess OK (6, 2, 3) call my_function (6, 2, 3) {'a': 'OK'} postprocessing 3 Out[1]: 10 In [2]:
@Круто ?! – Вы видите, как интерпретатор python анализирует вашу часть магии