簡體   English   中英

將可選的關鍵字參數傳遞給裝飾函數

[英]Passing optional keyword arguments to a decorated function

我想創建一個裝飾器,將可選關鍵字傳遞給它包裝的函數。 像這樣的東西:

@mydecorator
def dummy_without_magic_word():
  print('hello world')

@mydecorator
def dummy_with_magic_word(magic_word):
  print(magic_word)

基本上,如果被包裝的函數有一個特定的關鍵字,它應該由裝飾器提供; 否則,只需運行包裝的函數。

實現這一目標的正確方法是什么? 目前我只是想傳入關鍵字並檢查TypeError:

try:                                                                                           
  output = fn(redirect=redirect, **kwargs)                                               
except TypeError as e:
  if 'unexpected keyword argument' not in str(e):                                              
    raise e                                                                                    
  output = fn(*args, **kwargs)                                                           

但這似乎很脆弱/不直觀/奇怪。

為此,您可以使用inspect模塊。 使用getfullargspec函數,您可以訪問函數中定義的所有參數名稱。 一個注釋是,如果您想參數化傳遞給裝飾函數的默認值,您將需要一個裝飾器工廠。 這是一個代碼示例:

import inspect    

def my_decorator(default_value): # define decorator factory
    def decorator(fn): # define decorator
        def inner(*args, **kwargs): 
            fn_args = inspect.getfullargspec(fn).args # recover decorated function
                                                      # arguments
            
            if "magic_word" in fn_args: # check for argument
                return fn(*args, magic_word=default_value, **kwargs)
            else:
                return fn(*args, **kwargs)
        return inner
    return decorator

@my_decorator(default_value='Goodbye World')
def function_1():
    print('Hello World')

@my_decorator(default_value='Goodbye World')
def function_2(magic_word):
    print(magic_word)

使用此裝飾器,以下代碼的結果將是:

>>> function_1()
'Hello World'
>>> function_2()
'Goodbye World'

請注意,如果您只有關鍵字參數,則必須稍微修改裝飾器:

def my_decorator(default_value): # define decorator factory
    def decorator(fn): # define decorator
        def inner(*args, **kwargs): 
            fn_args = inspect.getfullargspec(fn).args # recover decorated function
                                                      # arguments
            fn_args += (inspect.getfullargspec(fn).kwonlyargs) # add kwonly args

            if "magic_word" in fn_args: # check for argument
                return fn(*args, magic_word=default_value, **kwargs)
            else:
                return fn(*args, **kwargs)
        return inner
    return decorator

@my_decorator(default_value='Goodbye World')
def function_3(a, *, magic_word):
    print(a, magic_word)

>>> function_3(1)
1 Goodbye World

請注意,此實現有一個重要的限制,即您必須對要查找的參數名稱進行硬編碼。 情況就是這樣,因為 python 無法計算參數名稱的表達式。 例如,如果您嘗試此實現:

def my_decorator(search_word, default_value): # define decorator factory
    def decorator(fn): # define decorator
        def inner(*args, **kwargs): 
            fn_args = inspect.getfullargspec(fn).args # recover decorated function
                                                      # arguments
            fn_args += (inspect.getfullargspec(fn).kwonlyargs) # add kwonly args

            if search_word in fn_args: # check for argument
                return fn(*args, search_word=default_value, **kwargs)
            else:
                return fn(*args, **kwargs)
        return inner
    return decorator

@my_decorator(search_word='magic_word', default_value='Goodbye World')
def function_4(magic_word):
    print(magic_word)

運行代碼會引發錯誤:

>>> function_4()
Traceback (most recent call last):
  File "/test.py", in <module>
    function_4()
  File "/test6.py", in inner
    return fn(*args, search_word=default_value, **kwargs)
TypeError: function_4() got an unexpected keyword argument 'search_word'

語法是這樣的:

def decorator(*args, **kwargs):
    print("Inside decorator")
     
    def inner(func):
         
        print("Inside inner function")
        print("I like", kwargs['param'])
         
        func()
         
    # reurning inner function   
    return inner
 
@decorator(param = "Hello world")
def my_func():
    print("Inside actual function")

或者:

@mydecorator
def dummy_with_magic_word(magic_word = 'hello world'):
  print(magic_word)

要檢查參數名稱,您可以像這樣深入研究函數對象:

arguments = fn.__code__.co_varnames[:fn.__code__.co_argcount]
if "redirect" in arguments:
    ...

暫無
暫無

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

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