首页 > 解决方案 > 确定 *args 是否提供来自装饰器的特定命名参数

问题描述

我有一个装饰器,在那个装饰器中我想检查被装饰的函数是否有一个带有 name 的参数query。如果它存在,我想像这样检测它的位置*argsargs[1]。我想在包装函数中执行此操作。我想做这样的事情:

def some_decorator(func):
    @wraps(func)
    def wrapper_func(*args, **kwargs):
        ind = 0
        query = ''
        for arg in args:
            if arg.__name__ == 'query'
                query = 'Found'
                break
            ind +=1
        if query == 'Found':
            query = args[ind]
    return wrapper_func

为了清楚起见,我这样使用它:

@some_decorator
def find_all(self, some_arg, query=None):
    pass

问题是,我也将装饰器用于其他功能,具有不同的签名,可能有也可能没有query参数。我希望这可以澄清事情。

标签: python

解决方案


如果我对您的理解正确,那么我认为您可以使用该inspect模块:

import inspect
...
def some_decorator(func):
    def wrapper_func(*args, **kwargs):
        # get function signature using inspect.signature()
        signature = inspect.signature(func)
        # find the subset of arguments that are positional-only
        positional_args = [name for name in signature.parameters 
                           if signature.parameters[name].kind in (inspect.Parameter.POSITIONAL_ONLY, inspect.Parameter.POSITIONAL_OR_KEYWORD)]
        # This should give us the names of args that *may* be positional. 
        # They should also be in the proper order, since positional-or-keyword args
        # cannot precede positional-only args.
        # Now, we can search for a positional arg named 'query', get an index...
        try:
            query_idx = positional_args.index('query')
        except ValueError:
            query_idx = -1
        # ... and extract the corresponding value passed for that in *args
        if 0 <= query_idx < len(args):
            query = args[query_idx]
        else:
            query = None
        # then do something with that
        ...
    return wrapper_func

推荐阅读