88 Глава 3 •
Эффективные функции
проблем, но имейте это в виду, если работаете над вычислительно емким
программным кодом, в котором декорирование применяется часто.
Декорирование функций,
принимающих аргументы
Все примеры пока что декорировали только простую
нульарную функ-
цию
greet
, которая вообще не принимала никаких аргументов. Вплоть
до этого момента декораторам, которые вы здесь видели, не было дела до
переадресации аргументов во входную функцию.
Если применить один из этих декораторов к функции, которая прини-
мает аргументы, то она не заработает правильно. Тогда как декорировать
функцию, которая принимает произвольные аргументы?
Вот где на помощь приходят функциональные средства языка Python
*args
и
**kwargs
для работы с неизвестными
количествами аргументов
1
.
Ниже приведен декоратор
proxy
, в котором задействуется их преимуще-
ство:
def proxy(func):
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
return wrapper
С этим декоратором
происходят две вещи, заслуживающие внимания:
В определении замыкания
wrapper
он использует операторы
*
и
**
,
чтобы собрать все позиционные и именованные аргументы, и помещает
их в переменные (
args
и
kwargs
).
Замыкание
wrapper
затем переадресует собранные аргументы в ори-
гинальную входную функцию, используя операторы «распаковки
аргументов» * и
**
.
К сожалению, в Python значение операторов «звездочка» и «двойная
звездочка» перегружено и меняется в зависимости от контекста, в котором
они
используются, но
надеюсь, вы уловили идею.
1
См. раздел 3.4 «Веселье с
*args
и
**kwargs
».
3 .3 . Сила декораторов
89
Давайте расширим прием, сформулированный декоратором
proxy
, в бо-
лее полезный практический пример. Ниже приведен декоратор
trace
,
который регистрирует аргументы функции и итоговые результаты, полу-
ченные во время исполнения:
def trace(func):
def wrapper(*args, **kwargs):
print(f'ТРАССИРОВКА: вызвана {func.__name__}() '
f'с {args}, {kwargs}')
original_result = func(*args, **kwargs)
print(f'ТРАССИРОВКА: {func.__name__}() '
f'вернула {original_result!r}')
return original_result
return wrapper
При декорировании функции с использованием декоратора
trace
и после-
дующем ее вызове, будут выведены переданные в декорированную функ-
цию аргументы и возвращаемое ею значение. Этот пример по-прежнему
остается несколько «игрушечным» — но в случае крайней необходимости
он становится отличным средством отладки:
@trace def say(name, line):
return f'{name}: {line}'
>>> say('Джейн', 'Привет, Мир')
Do'stlaringiz bilan baham: