以前項目需求,須要經過反射獲取函數的參數,python中能夠經過函數簽名(signature)來實現。python
首先須要瞭解函數參數的類型,Python的參數類型一共有5種:POSITIONAL_OR_KEYWORD(定位或關鍵字)、VAR_POSITIONAL(定位)、VAR_KEYWORD(關鍵字)、KEYWORD_ONLY(僅有關鍵字)、POSITIONAL_ONLY(僅有定位)app
其中 POSITIONAL_OR_KEYWORD、VAR_POSITIONAL、VAR_KEYWORD、KEYWORD_ONLY 比較經常使用函數
參數類型爲VAR_POSITIONAL時,即*args參數,只能經過位置傳值,如orm
def say_hello(*args): print('hello {0}'.format(args)) # 經過位置傳值 say_hello('jack', 'tom')
參數類型爲VAR_KEYWORD,即 **kwargs參數,只能經過關鍵字傳值,如it
def func_b(**kwargs): print(kwargs) # 經過關鍵字傳值 func_b(a=1, b=2)
參數的類型爲POSITIONAL_OR_KEYWORD時,說明此參數前面沒有VAR_POSITIONAL類型的參數,能夠經過位置或關鍵字傳值,如form
def say_hello(name): print('hello {0}'.format(name)) # 經過位置傳值 say_hello('jack') # 經過關鍵字傳值 say_hello(name='tom')
參數類型爲KEYWORD_ONLY時,說明此參數前面存在VAR_POSITIONAL類型的參數,只能經過關鍵字傳值,如class
def func_b(*args, a, b): print(args, a, b) # 只能經過關鍵字傳值 func_b('test', a=1, b=2)
比較特別的是POSITIONAL_ONLY,只能經過位置傳值的參數。Python並無明確的語法去定義一個只能經過位置傳值的函數參數,可是在不少內置和擴展模塊的函數會接受這種類型的參數。test
實際獲取函數參數時,須要用到inspect模塊,經過這個模塊的signature方法獲取函數簽名。import
import inspect def func_a(arg_a, *args, arg_b='hello', **kwargs): print(arg_a, arg_b, args, kwargs) if __name__ == '__main__': # 獲取函數簽名 func_signature = inspect.signature(func_a) func_args = [] # 獲取函數全部參數 for k, v in func_signature.parameters.items(): # 獲取函數參數後,須要判斷參數類型 # 當kind爲 POSITIONAL_OR_KEYWORD,說明在這個參數以前沒有任何相似*args的參數,那這個函數能夠經過參數位置或者參數關鍵字進行調用 # 這兩種參數要另外作判斷 if str(v.kind) in ('POSITIONAL_OR_KEYWORD', 'KEYWORD_ONLY'): # 經過v.default能夠獲取到參數的默認值 # 若是參數沒有默認值,則default的值爲:class inspect_empty # 因此經過v.default的__name__ 來判斷是否是_empty 若是是_empty表明沒有默認值 # 同時,由於類自己是type類的實例,因此使用isinstance判斷是否是type類的實例 if isinstance(v.default, type) and v.default.__name__ == '_empty': func_args.append({k: None}) else: func_args.append({k: v.default}) # 當kind爲 VAR_POSITIONAL時,說明參數是相似*args elif str(v.kind) == 'VAR_POSITIONAL': args_list = [] func_args.append(args_list) # 當kind爲 VAR_KEYWORD時,說明參數是相似**kwargs elif str(v.kind) == 'VAR_KEYWORD': args_dict = {} func_args.append(args_dict) print(func_args)