Расширить декоратор экземпляра, чтобы принимать параметры ключевого значения?

#python #python-decorators

#python #python-декораторы

Вопрос:

У меня есть следующий декоратор экземпляра класса, и он работает нормально.

 class KD:
    def __init__(self, a, b):
        self.enabled = True
        self.a = a
        self.b = b
     
    def __call__(self, f):

        def wrap(*arg, **kwargs):
            if self.enabled == True:
                print(f'wrap... {self.a}') # may need other parameters

            return f(*arg, **kwargs)

        return wrap
  

В следующем примере показано, как использовать его для оформления функции test1 .

 kd = KD(10)
#kd.enabled = False

@kd
def test1(x):
    return x

test1('abc')
  

Теперь я хочу передать дополнительные необязательные параметры wrap функции в декораторе. Например,

 kd = KD(10)

@kd() # no parameter to pass to the wrap function
def test1(x):
    return x

@kd(p1='xyz') # one pw parameter is passed to the wrap function
def test2(x):
    return x

@kd(p1='xyz', p2=30) # two pw parameters are passed to the wrap function
def test3(x):
    return x
  

Это способ его реализации?

Ответ №1:

Да, есть стандартный способ сделать это:

 def __call__(self, **outer_kwargs):
    def actual_decorator(f):
        # use outer_kwargs
        def wrap(*arg, **kwargs):
            if self.enabled == True:
                print(f'wrap... {self.a}') # may need other parameters

            return f(*arg, **kwargs)

        return wrap
    return actual_decorator
  

Ответ №2:

Одним полным примером может быть :

 class SimpleDecor(object):

    def __init__(self, *args, **kwargs):
        self.args = args
        self.kwargs = kwargs

    def __call__(self, f):
        def wrapped_f(*args, **kwargs):
            print("Args to class {}".format(self.args))
            print("K-Args to class ({})".format(' '.join('%s=%s' % (k, v) for k, v in self.kwargs.items())))
            #Do something here
            print("Args to fuction ({})".format(args))
            print("K-Args to fuction ({})".format(' '.join('%s=%s' % (k, v) for k, v in kwargs.items())))
            return f(*args, **kwargs)
        return wrapped_f


@SimpleDecor('This', 'is', 'class', 'argument', version=1)
def sayHello(fname, lastname, age, initial):
    return '{} {} {} is {} year old'.format(initial, fname, lastname, age)


print(sayHello('Abc', 'Xyz', initial='Mr', age =90))

  

Если вы выполните, вы получите результат :

 Args to class ('This', 'is', 'class', 'argument')
K-Args to class (version=1)
Args to fuction (('Abc', 'Xyz'))
K-Args to fuction (initial=Mr age=90)
Mr Abc Xyz is 90 year old