Декораторы в питоне - удобный инструмент. Если ими пользоваться с умом, они значительно повышают читаемость кода и его повторное использование. Но есть один момент, который меня немного напрягает: для декоратора с параметрами по умолчанию нужно ставить пустые круглые скобки после его вызова. Время от времени, это приводит к ошибкам. Особенно это актуально, если декоратор является частью публичного 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 будет глаза мозолить. С другой стороны, код практически не усложнился, читаемость не снизилась.

Вот еще пара интересных вариантов реализации декораторов с параметрами, на которые можно посмотреть. Возможно, для ваших проектов они окажутся более подходящими:



c