Параметризованные декораторы, которые разделяют внутренние функции

#python #decorator #python-decorators

Вопрос:

Я пытаюсь создать два очень похожих декоратора, каждый из которых принимает общие args и kwargs , и оба из которых внутренне разделяют код. Единственное различие между их двумя определениями заключается в значении определенного флага (который не предоставляется пользователю). Полный контекст содержится в этом вопросе.

В настоящее время у меня есть первый декоратор, определенный (без ссылки на флаг) как

 import functools


def decorator_factory(*args_units, **kwargs_units):

    def _decorator(func):
        @functools.wraps(func)
        def _wrapper(*args, **kwargs):
            return f(*args, **kwargs, *args_units, **kwargs_units)

        return _wrapper
    return _decorator
 

который можно использовать следующим образом

 @decorator_factory(*args_units, **kwargs_units)
def func_to_be_decorated(*args, **kwargs):
    ...
 

Вместо этого я хочу создать двух очень похожих декораторов, что-то вроде этого

 def decorator_factory1(*args_units, **kwargs_units):
    return functools.partial(_decorator, flag=True)


def decorator_factory2(*args_units, **kwargs_units):
    return functools.partial(_decorator, flag=False)


def _decorator(func, flag):
    @functools.wraps(func)
    def _wrapper(*args, **kwargs):
        if flag:
            return f1(*args, **kwargs, *args_units, **kwargs_units)
        else:
            return f2(*args, **kwargs, *args_units, **kwargs_units)

    return _wrapper
 

который затем можно было бы использовать следующим образом

 @decorator_factory1(*args_units, **kwargs_units)
def func1_to_be_decorated(*args, **kwargs):
    ...


@decorator_factory2(*args_units, **kwargs_units)
def func2_to_be_decorated(*args, **kwargs):
    ...
 

Проблема в том , что этот шаблон не передается *args_units и **kwargs_units , поскольку они больше недоступны в локальном пространстве имен внутри _decorator функции.

Комментарии:

1. где определены f , f1 , f2 ?

2. какую ошибку вы получаете, когда используете этот способ f1(*args, **kwargs, *args_units, **kwargs_units) ? кстати, вам нужно передать параметр в следующем порядке f1(*args, *args_units, **kwargs, **kwargs_units)

3. вы можете объединить два декоратора decorator_factory1 amp; 2 в один, параметризовав атрибут flag как, например, smt как class Dec: def __init__(self, flag): self.flag = flag ; def decorator_factory(self, *args_units, **kwargs_units): return functools.partial(_decorator, flag=self.flag) и назвать его как @Dec(True).decorator_factory(...) … просто идея

4. … и чтобы устранить *args, **kwargs, *args_units, **kwargs_units проблему, вы могли бы выполнить вложенный functools.partial вызов, в котором в каждом вызове вы передаете другое «семейство» аргументов.

5. Где/когда вы ожидаете, что фактические значения **args_units и **kwargs_units будут получены в @ строке ? Декоратор выполняется во время компиляции, поэтому там нет значений, если только у вас нет этих двух в глобальных переменных.