Декораторы с параметрами по умолчанию
Опубликовано 03 August 2015 в Python
Декораторы в питоне - удобный инструмент. Если ими пользоваться с умом, они значительно повышают читаемость кода и его повторное использование. Но есть один момент, который меня немного напрягает: для декоратора с параметрами по умолчанию нужно ставить пустые круглые скобки после его вызова. Время от времени, это приводит к ошибкам. Особенно это актуально, если декоратор является частью публичного API.
@decorator_wo_params
def f1 ():
pass
@decorator_w_defaults_params() # ну зачем здесь пустые скобки?
def f2 ():
pass
С этим можно смириться. В режиме жестких сроков и большого потока задач, времени на поиск решения, написание и тестирование дополнительного кода может просто не быть. Нормальное тестирование выявит проблему моментально. Но иногда невозможно удержаться и не сделать свой код немного красивее.
Предположим, что требуется декоратор, который увеличивает значение функции в заданное количество раз. По умолчанию - в 10 раз. У меня получился следующий код:
from functools import wraps
def multiplicator(method=None, rate=10):
def decorator(method):
@wraps(method)
def wrapper(*args, **kwargs):
return rate*method(*args, **kwargs)
return wrapper
if callable(method):
return decorator(method)
return decorator
В основе лежит идея предложенная Михаэлем Анджелетти на StackOverflow (Python - making decorators with optional arguments). Я немного модифицировал его код под поставленную задачу. Но идея сохранена. Если декоратор вызван без скобочек, то первым параметрам в функцию multiplicator прилетит функция. Если же вызвать со скобочками (не важно с параметрами или нет), то в if мы не попадаем. Возвращается декоратор.
Код рабочий, но не без проблем. Параметры в подобный декоратор нужно передавать по имени. Что не всегда удобно. Да и непонятный method в подсказке IDE будет глаза мозолить. С другой стороны, код практически не усложнился, читаемость не снизилась.
Вот еще пара интересных вариантов реализации декораторов с параметрами, на которые можно посмотреть. Возможно, для ваших проектов они окажутся более подходящими:
Возник вопрос? Мне всегда можно написать в Twitter: avkorablev