我正在尝试编写一个装饰器,它保留了它所装饰的函数的参数。这样做的动机是编写一个与pytest.fixtures
很好地交互的装饰器。
假设我们有一个函数foo
。它需要一个参数a
。
def foo(a):
pass
如果我们得到foo的论证规范
>>> inspect.getargspec(foo)
ArgSpec(args=['a'], varargs=None, keywords=None, defaults=None)
我们经常想要创建一个装饰器,wrapper
函数将其所有参数逐字传递给wrapped
函数。最明显的方法是使用*args
和**kwargs
。
def identity_decorator(wrapped):
def wrapper(*args, **kwargs):
return wrapped(*args, **kwargs)
return wrapper
def identity_decorator(wrapped):
def wrapper(*args, **kwargs):
return wrapped(*args, **kwargs)
return wrapper
@identity_decorator
def foo(a):
pass
这不足为奇地产生了一个带有反映*args
和**kwargs
的参数规范的函数。
>>> inspect.getargspec(foo)
ArgSpec(args=[], varargs='args', keywords='kwargs', defaults=None)
有没有办法更改参数规范以匹配包装函数或者最初使用正确的参数规范创建函数?
答案 0 :(得分:3)
AFAIK,只有Python 3.3才能使用Signature
对象:
def identity_decorator(wrapped):
def wrapper(*args, **kwargs):
return wrapped(*args, **kwargs)
wrapper.__signature__ = inspect.signature(wrapped) # the magic is here!
return wrapper
然后,你可以这样做:
@identity_decorator
def foo(a):
pass
最后:
>>> inspect.getargspec(foo)
ArgSpec(args=['a'], varargs=None, keywords=None, defaults=None)
答案 1 :(得分:2)
根据评论中的建议,您可以使用decorator模块,也可以使用password
邪恶力量创建具有正确签名的lambda函数:
eval
这有点像hackish,但它保留了函数参数:
import inspect
def identity_decorator(wrapped):
argspec = inspect.getargspec(wrapped)
args = inspect.formatargspec(*argspec)
def wrapper(*args, **kwargs):
return wrapped(*args, **kwargs)
func = eval('lambda %s: wrapper%s' % (args.strip('()'), args), locals())
return func
@identity_decorator
def foo(a):
pass