如何将函数参数传递给装饰器

时间:2015-11-13 11:09:11

标签: python python-3.x twisted python-decorators

我正在使用装饰器: deferred_set_context 将功能模块,名称和时间设置为上下文字符串(基本上需要此上下文来跟踪多次调用 register_request < /强>)

@deferred_set_context()    
def register_request(self, machine_model):

def deferred_set_context(name=None):
    def __outer__(func):
        context_name = name
        if not context_name:
            context_name = func.__name__

        @defer.inlineCallbacks
        def __inner__(*args, **kwargs):
            r = None
            with base.this_context_if_no_context(base.Context('%s.%s.%s' % (func.__module__, context_name,
                                                                         datetime.utcnow().strftime(
                                                                             '%Y-%m-%dT%H:%M:%S.%f')))):
                r = yield func(*args, **kwargs)
            defer.returnValue(r)

        return __inner__
    return __outer__

现在我需要设置将 machine_model 名称( register_request 的参数)传递给此装饰器: register_request 。像这样:

@deferred_set_context(name=machine_model)    
def register_request(self, machine_model):

我该怎么做?

3 个答案:

答案 0 :(得分:1)

请注意,以下两个代码段是等效的

# first
@decorator
def func():
    pass

# second
def func():
    pass
func = decorator(func)

你需要让你的装饰者把一个函数作为一个参数。如果要将name作为变量传递,那么它应该是装饰器返回的函数中的参数。

答案 1 :(得分:1)

假设您不想更改deferred_set_contextregister_request的行为,您可以制作第二个shim装饰器,它会侦测正确的函数参数并将其传递给原始装饰器。< / p>

这样的事情:

def new_shim_decorator(register_request):
    def wrapper(self, machine_model):
        return deferred_set_context(machine_model)(self, machine_model)
    return wrapper

@new_shim_decorator
def register_request(self, machine_model):
    print("my_function called with {}".format(machine_model))

在我看来,这是一种hacky解决方案,因为这个装饰器代理原始装饰器需要知道传递给register_request并反映它们的参数。

我更希望看到一个只有关键字的参数,可以选择get - 来自shim decorator中的关键字参数字典或原始的:

def deferred_set_context_by_kwarg(kwarg_name):
    def outer(func):
        def wrapper(*args, **kwargs):
            return deferred_set_context(name=kwargs.get(kwarg_name))(*args, **kwargs)
        return wrapper
    return outer

@deferred_set_context_by_kwarg('machine_model')
def register_request(self, *, machine_model):
    print("my_function called with {}".format(machine_model))

注意*, machine_model*是一个Python 3功能,需要将machine_model指定为关键字参数。这允许我们的deferred_set_context_by_kwarg装饰器接受表示我们想要的关键字参数名称的字符串,并使用该名称来检索关键字参数值,并在每次函数调用时传递给deferred_set_context

答案 2 :(得分:0)

如果你确定你的函数register_request总是使用相同的2个参数,那么在装饰器代码中选择它们。