[英]Python create decorator preserving function arguments
我正在嘗試編寫一個裝飾器來保留它所裝飾的函數的參數。 這樣做的動機是編寫一個與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
@identity_decorator
def foo(a):
pass
毫不奇怪,這會產生一個函數,其參數規范反映了*args
和**kwargs
。
>>> inspect.getargspec(foo)
ArgSpec(args=[], varargs='args', keywords='kwargs', defaults=None)
有沒有辦法更改參數規范以匹配包裝的函數或最初使用正確的參數規范創建函數?
AFAIK,只有從帶有Signature
對象的 Python 3.3 開始才有可能:
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)
正如評論中所建議的,您可以使用裝飾器模塊,也可以使用eval
邪惡力量創建具有正確簽名的 lambda 函數:
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
這有點hackish,但它保留了函數參數:
>>> inspect.getargspec(foo)
ArgSpec(args=['a'], varargs=None, keywords=None, defaults=None)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.