Python 检查并实时修改来自装饰程序的调用参数

Python 检查并实时修改来自装饰程序的调用参数,python,python-2.7,Python,Python 2.7,我的用例如下所示: @AddOne("b") def func(a, b, c, *args, **kwargs): print a, b, c class AddOne(object): def __init__(self, param_name): self.param_name = param_name def __call__(self, func): @wraps(func) def decorated(*ar

我的用例如下所示:

@AddOne("b")
def func(a, b, c, *args, **kwargs):
    print a, b, c
class AddOne(object):
    def __init__(self, param_name):
        self.param_name = param_name

    def __call__(self, func):
        @wraps(func)
        def decorated(*args, **kwargs):
            new_args = list(args)
            new_kwargs = kwargs

            v = extract_parameter_somehow(
                func, new_args, kwargs, 
                self.param_name) + 1

            kwargs[self.param_name] = v
            return func(*new_args, **kwargs)
        return decorated
预期行为:

>>> func(1, 2, 3)
1 3 3
>>> func(a=1, c=3, b=2)
1 3 3
我怀疑我必须在使用
inspect
模块时使用
getcallargs
getargspec
之类的东西对decorator进行编码,但我无法以编程方式执行它。我错过什么了吗

编辑:我的尝试如下:

@AddOne("b")
def func(a, b, c, *args, **kwargs):
    print a, b, c
class AddOne(object):
    def __init__(self, param_name):
        self.param_name = param_name

    def __call__(self, func):
        @wraps(func)
        def decorated(*args, **kwargs):
            new_args = list(args)
            new_kwargs = kwargs

            v = extract_parameter_somehow(
                func, new_args, kwargs, 
                self.param_name) + 1

            kwargs[self.param_name] = v
            return func(*new_args, **kwargs)
        return decorated
一个选项(可能有点黑客?)是使用
getargspec
,然后对
args
kwargs

# ...
    def __call__(self, func):
        arg_names = getargspec(func).args
        self.param_index = arg_names.index(self.param_name)

        @wraps(func)
        def decorated(*args, **kwargs):
            new_args = list(args)
            new_kwargs = kwargs

            try:
                v = new_args.pop(self.param_index)
            except IndexError:
                v = new_kwargs.pop(self.param_name) 
            new_kwargs[self.param_name] = v + 1
            return func(*new_args, **new_kwargs)
        return decorated

模块
inspect
包含满足要求所需的所有内容:

  • getargspec
    提供了了解参数及其顺序的准确定义
  • getcallargs
    处理实际参数并给出它们的值
代码可以是:

 class AddOne(object):
    def __init__(self, param_name):
        self.param_name = param_name

    def __call__(self, func):
        self.argspec = inspect.getargspec(func)
        @wraps(func)
        def decorated(*args, **kwargs):
            callargs = inspect.getcallargs(func, *args, **kwargs)
            if callargs.has_key(self.param_name):
        callargs[self.param_name] += 1
        elif callargs[self.argspec.keywords].has_key(self.param_name):
        callargs[self.argspec.keywords][self.param_name] += 1
            new_args = [ callargs[i] for i in self.argspec.args
             ] + list(callargs[self.argspec.varargs])
            new_kwargs = callargs[self.argspec.keywords]
            return func(*new_args, **kwargs)
        return decorated
这意味着:

  • 使用getcallargs处理作为键控参数给定的默认值和位置参数
  • 在位置参数中搜索参数名称-如果找到,增加相应的值
  • 如果在位置参数中找不到,请在关键字参数中搜索-如果找到,请增加相应的值

然后,根据
getcallargs
返回值构建位置参数列表和关键字参数的哈希,以允许额外的varargs或其他关键字参数。

你的装饰器看起来像什么?@idjaw是的,我刚刚编辑了这篇文章。我意识到我的“正在进行的工作”源代码没有适应以下问题:-/我多任务处理太多了…谢谢!我已经找到了
getcallargs
的东西,但是我搞砸了,因为我不理解
varargs
关键字,它们是问题的关键。