Декораторы в 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

В основе лежит идея, предложенная Михаэлем Анджелетти на Stack Overflow (Python — making decorators with optional arguments). Я немного модифицировал его код под поставленную задачу, но идея сохранена.

Если декоратор вызван без скобок, то первым параметром в функцию multiplicator прилетит функция. Если же вызвать со скобками (не важно, с параметрами или нет), то в if мы не попадаем — возвращается декоратор.

Код рабочий, но не без проблем:

  • параметры в подобный декоратор нужно передавать по имени, что не всегда удобно;
  • непонятный method в подсказке IDE будет глаза мозолить.

С другой стороны, код практически не усложнился, читаемость не снизилась.

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