簡體   English   中英

Python 創建裝飾器保留函數參數

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM