如何在Python装饰器中以编程方式更改函数的argspec?

13 投票
3 回答
3087 浏览
提问于 2025-04-16 04:14

给定一个函数:

def func(f1, kw='default'):
    pass
bare_argspec = inspect.getargspec(func)

@decorator
def func2(f1, kw='default'):
    pass
decorated_argspec = inspect.getargspec(func2)

我该如何创建一个装饰器,使得 bare_argspec == decorated_argspec 呢?

(至于原因,调用这个装饰过的函数的框架会检查参数规格,以决定传递什么参数,所以这个装饰器必须保持相同的参数规格,这样才能正常工作。当我在 #python 上提出这个问题时,得到了很多关于这个框架不好的长篇大论,但这不是我想要的;我需要在这里解决问题。此外,我也只是对答案感兴趣。)

3 个回答

0

functools.update_wrapper()functools.wraps() 这两个工具好用吗?

2

这里有一个叫做 decorator 的模块:

from decorator import decorator
@decorator
def trace(func, *args, **kw):
    print 'calling', func, 'with', args, kw
    return func(*args, **kw)

这个模块让 trace 成为一个装饰器,它的参数和被装饰的函数是一样的。举个例子:

>>> @trace
... def f(x, y=1, z=2, *args, **kw):
...     pass

>>> f(0, 3)
calling f with (0, 3, 2), {}

>>> from inspect import getargspec
>>> print getargspec(f)
ArgSpec(args=['x', 'y', 'z'], varargs='args', keywords='kw', defaults=(1, 2))
13

Michele Simionato的decorator模块里有一个叫做decorator的装饰器,它可以保留函数的参数信息。

import inspect
import decorator

def func(f1, kw='default'):
    pass
bare_argspec = inspect.getargspec(func)
print(bare_argspec)
# ArgSpec(args=['f1', 'kw'], varargs=None, keywords=None, defaults=('default',))

@decorator.decorator
def mydecorator(func,*args,**kw):
    result=func(*args,**kw)
    return result

@mydecorator
def func2(f1, kw='default'):
    pass
decorated_argspec = inspect.getargspec(func2)
print(decorated_argspec)
# ArgSpec(args=['f1', 'kw'], varargs=None, keywords=None, defaults=('default',))

assert(bare_argspec==decorated_argspec)

撰写回答