對函數部分或全部參數進行類型檢查


對函數部分或全部參數進行類型檢查

構建一個裝飾器,通過對裝飾器中傳入類型參數,來對裝飾的函數的對應參數進行類型檢查。

from inspect import signature
from functools import wraps

def typeassert(*tyargs,**tykwargs):
   def decorator(func):
       #獲取指定的強制類型參數
       sig=signature(func)
       required_types=sig.bind_partial(*tyargs,**tykwargs).arguments#OrderedDict類型,可以只對前面的參數進行in搜索判定,可以把前面的參數當作key來獲取對應的類型

       @wraps(func)
       def wrapper(*args,**kwargs):
           #獲取函數輸入的各參數類型
           input_vals=sig.bind(*args,**kwargs)

           #對輸入的每個參數,如果出現在設定的類型檢查中,則進行類型檢查
           for name,value in input_vals.arguments.items():
               if name in required_types:
                   if not isinstance(value,required_types[name]):
                       raise TypeError(
                           'Argument {} must be {}'.format(name, required_types[name])
                          )
           return func(*args,**kwargs)
       return wrapper
   return decorator

@typeassert(str,z=int)#第一個位置參數為str,z必須為int
def func(x,y,z):
   return y+z

>>>print(func(1,2,3))
TypeError: Argument x must be <class 'str'>
   
@typeassert(int,y=str,z=int)#第一個位置參數為int,y為str,z必須為int
def func(x,y,z):
   print(x,y,z)
>>>func1(3,'s',1)
3 s 1
>>>func1('hhh','s',1)
TypeError: Argument x must be <class 'int'>

另外也可以通過函數注解來實現,之前實現過,代碼如下:

def para_check(func):#外函數,傳入的參數是待檢驗函數對象本身
   sig=inspect.signature(func)#獲取函數參數簽名
   parameters=sig.parameters#獲取參數的有序字典
   arg_names=tuple(parameters.keys())#獲取參數的名稱
   def wrapper(*args,**kwargs):#內函數
       check_list=[]#待檢驗的參數對
       for i,val in enumerate(args):#檢驗所有的位置參數
           arg_name=arg_names[i]
           anno=parameters[arg_name].annotation#該參數期待的類型
           check_list.append((arg_name,anno,val))
       for arg_name,val in kwargs.items():#檢驗所有的關鍵字參數
           anno=parameters[arg_name].annotation
           check_list.append((arg_name,anno,val))

       for check_arg in check_list:#逐個參數檢驗
           if not isinstance(check_arg[2],check_arg[1]):
               raise TypeError('the input %s expect type %s,but got %s'%(check_arg[0],check_arg[1],type(check_arg[2])))
       return func(*args,**kwargs)
   return wrapper

@para_check
def test(x: int, y: int):
   return x + y
>>>print(test(1,2))
3
>>>print(test(1,'3'))
TypeError: the input y expect type <class 'int'>,but got <class 'str'>

后者不需要使用傳參數的裝飾器。但是明顯前者更靈活,用前者進行類型檢查,那么后面的函數注解就可以做其它事情而非類型檢查了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM