簡體   English   中英

將默認參數傳遞給python中的裝飾器

[英]Passing default arguments to a decorator in python

我試圖找到一種方法將我的函數的默認參數傳遞給裝飾器。 我不得不說我對裝飾業務還很陌生,所以也許我只是沒有正確理解它,但我還沒有找到任何答案。

所以這是我從 Python functools.wraps手冊頁修改的示例。

from functools import wraps
def my_decorator(f):
    @wraps(f)
    def wrapper(*args, **kwds):
            print('Calling decorated function')
            print('args:', args)
            print('kwargs:', kwds)
            return f(*args, **kwds)
    return wrapper

@my_decorator
def example(i, j=0):
    """Docstring"""
    print('Called example function')

example(i=1)

我也希望j=0被傳遞。 所以輸出應該是:

Calling decorated function
args: ()
kwargs: {'i': 1, 'j': 0}
Called example function

但相反我得到

Calling decorated function
args: ()
kwargs: {'i': 1}
Called example function

默認參數是函數簽名的一部分。 它們不存在於裝飾器調用中。

要在包裝器中訪問它們,您需要將它們從函數中取出,如本問題所示。

import inspect
from functools import wraps

def get_default_args(func):
    signature = inspect.signature(func)
    return {
        k: v.default
        for k, v in signature.parameters.items()
        if v.default is not inspect.Parameter.empty
    }

def my_decorator(f):
    @wraps(f)
    def wrapper(*args, **kwds):
            print('Calling decorated function')
            print('args:', args)
            kwargs = get_default_args(f)
            kwargs.update(kwds)
            print('kwargs:', kwargs)
            return f(*args, **kwds)
    return wrapper

@my_decorator
def example(i, j=0):
    """Docstring"""
    print('Called example function')

example(i=1)

輸出:

Calling decorated function
args: ()
kwargs: {'i': 1, 'j': 0}
Called example function

您可以使用__defaults__特殊屬性獲取默認參數值。

def my_decorator(f):
@wraps(f)
def wrapper(*args, **kwds):
    print('def args values', f.__defaults__)
    return f(*args, **kwds)
return wrapper

參考:在https://docs.python.org/3/reference/datamodel.html#the-standard-type-hierarchy 中查找__defaults__

包含具有默認值的參數的默認參數值的元組,如果沒有參數具有默認值,則為 None

獲取 args 和 kwargs 的確切列表有點棘手,因為您可以將位置 args 作為 kwarg 傳遞,反之亦然。 較新版本的 python 還添加了僅位置參數或僅關鍵字參數。

但是, inspect.signature有一種可以應用默認值的機制:調用.bind(*args, **kwargs)后跟.apply_defaults() 這可以為您提供一個有效的字典,其中包含函數的所有參數。 在 OP 的示例中,這變為:

from functools import wraps
import inspect
def my_decorator(f):
    sig = inspect.signature(f)
    @wraps(f)
    def wrapper(*args, **kwds):
        bound = sig.bind(*args, **kwds)
        bound.apply_defaults()
        print('Calling decorated function')
        print('called with:', bound.arguments)
        return f(*args, **kwds)
    return wrapper

@my_decorator
def example(i, j=0):
    """Docstring"""
    print('Called example function')

example(i=1)

這會在 Python 3.9 上輸出以下內容:

Calling decorated function
called with: OrderedDict([('i', 1), ('j', 0)])
Called example function

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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