Python入門篇-類型註解
python
做者:尹正傑程序員
版權聲明:原創做品,謝絕轉載!不然將追究法律責任。app
一.函數定義的弊端ide
1>.動態語言很靈活,可是這種特性也是弊端函數
Python是動態語言,變量隨時能夠被賦值,且能賦值爲不一樣的類型 Python不是靜態編譯型語言,變量類型是在運行器決定的 動態語言很靈活,可是這種特性也是弊端 def add(x, y): return x + y print(add(4, 5)) print(add('hello', 'world')) add(4, 'hello') 難發現:因爲不作任何類型檢查,直到運行期問題才顯現出來,或者線上運行時才能暴露出問題 難使用:函數的使用者看到函數的時候,並不知道你的函數的設計,並不知道應該傳入什麼類型的數據
2>.如何解決這種動態語言定義的弊端工具
增長文檔Documentation String 這只是一個慣例,不是強制標準,不能要求程序員必定爲函數提供說明文檔 函數定義更新了,文檔未必同步更新 def add(x, y): ''' :param x: int :param y: int :return: int ''' return x + y print(help(add))
3>.函數註解ui
1 #!/usr/bin/env python 2 #_*_coding:utf-8_*_ 3 #@author :yinzhengjie 4 #blog:http://www.cnblogs.com/yinzhengjie/tag/python%E8%87%AA%E5%8A%A8%E5%8C%96%E8%BF%90%E7%BB%B4%E4%B9%8B%E8%B7%AF/ 5 #EMAIL:y1053419035@qq.com 6 7 8 def add(x:int , y:int) -> int : 9 ''' 10 :param x: int 11 :param y: int 12 :return: int 13 ''' 14 return x + y 15 16 print(help(add)) 17 print(add(4, 5)) 18 print(add('Yin', 'zhengjie')) 19 20 21 22 23 #以上代碼執行結果以下: 24 Help on function add in module __main__: 25 26 add(x:int, y:int) -> int 27 :param x: int 28 :param y: int 29 :return: int 30 31 None 32 9 33 Yinzhengjie
二.函數註解Function Annotationsspa
1>.函數註解設計
Python 3.5引入
對函數的參數進行類型註解
對函數的返回值進行類型註解
只對函數參數作一個輔助的說明,並不對函數參數進行類型檢查
提供給第三方工具,作代碼分析,發現隱藏的bug
函數註解的信息,保存在__annotations__屬性中
2>.變量註解code
Python 3.6引入變量註解
i : int = 3
三.業務應用-函數參數類型檢查
1>.思路
函數參數的檢查,必定是在函數外 函數應該做爲參數,傳入到檢查函數中 檢查函數拿到函數傳入的實際參數,與形參聲明對比 __annotations__屬性是一個字典,其中包括返回值類型的聲明。假設要作位置參數的判斷,沒法和字典中的聲明對應。使用inspect模塊
2>.inspet模塊
1 #!/usr/bin/env python 2 #_*_coding:utf-8_*_ 3 #@author :yinzhengjie 4 #blog:http://www.cnblogs.com/yinzhengjie/tag/python%E8%87%AA%E5%8A%A8%E5%8C%96%E8%BF%90%E7%BB%B4%E4%B9%8B%E8%B7%AF/ 5 #EMAIL:y1053419035@qq.com 6 7 import inspect 8 """ 9 signature(callable): 10 獲取簽名(函數簽名包含了一個函數的信息,包括函數名、它的參數類型、它所在的類和名稱空間及其餘信息) 11 """ 12 13 def add(x:int, y:int, *args,**kwargs) -> int: 14 return x + y 15 16 print(add.__annotations__) #不推薦使用它,返回的結果是無序的 17 18 sig = inspect.signature(add) 19 print(sig, type(sig)) # 函數簽名 20 print('params : ', sig.parameters) # OrderedDict,即返回的結果是一個有序字典 21 print('return : ', sig.return_annotation) 22 print(sig.parameters['y'], type(sig.parameters['y'])) 23 print(sig.parameters['x'].annotation) 24 print(sig.parameters['args']) 25 print(sig.parameters['args'].annotation) 26 print(sig.parameters['kwargs']) 27 print(sig.parameters['kwargs'].annotation) 28 print("是不是函數:{}".format(inspect.isfunction(add))) 29 print("是不是類的方法:{}".format(inspect.ismethod(add))) 30 print("是不是生成器對象:{}".format(inspect.isgenerator(add))) 31 print("是不是生成器函數:{}".format(inspect.isgeneratorfunction(add))) 32 print("是不是類:{}".format(inspect.isclass(add))) 33 print("是不是模塊:{}".format(inspect.ismodule(inspect))) 34 print("是不是內建對象:{}".format(inspect.isbuiltin(print))) #還有不少is函數,須要的時候查閱inspect模塊幫助 35 36 37 38 39 #以上代碼執行結果以下: 40 {'x': <class 'int'>, 'y': <class 'int'>, 'return': <class 'int'>} 41 (x:int, y:int, *args, **kwargs) -> int <class 'inspect.Signature'> 42 params : OrderedDict([('x', <Parameter "x:int">), ('y', <Parameter "y:int">), ('args', <Parameter "*args">), ('kwargs', <Parameter "**kwargs">)]) 43 return : <class 'int'> 44 y:int <class 'inspect.Parameter'> 45 <class 'int'> 46 *args 47 <class 'inspect._empty'> 48 **kwargs 49 <class 'inspect._empty'> 50 是不是函數:True 51 是不是類的方法:False 52 是不是生成器對象:False 53 是不是生成器函數:False 54 是不是類:False 55 是不是模塊:True 56 是不是內建對象:True
1 #!/usr/bin/env python 2 #_*_coding:utf-8_*_ 3 #@author :yinzhengjie 4 #blog:http://www.cnblogs.com/yinzhengjie/tag/python%E8%87%AA%E5%8A%A8%E5%8C%96%E8%BF%90%E7%BB%B4%E4%B9%8B%E8%B7%AF/ 5 #EMAIL:y1053419035@qq.com 6 7 import inspect 8 """ 9 Parameter對象 10 保存在元組中,是隻讀的 11 name,參數的名字 12 annotation,參數的註解,可能沒有定義 13 default,參數的缺省值,可能沒有定義 14 empty,特殊的類,用來標記default屬性或者註釋annotation屬性的空值 15 kind,實參如何綁定到形參,就是形參的類型 16 POSITIONAL_ONLY,值必須是位置參數提供 17 POSITIONAL_OR_KEYWORD,值能夠做爲關鍵字或者位置參數提供 18 VAR_POSITIONAL,可變位置參數,對應*args 19 KEYWORD_ONLY,keyword-only參數,對應*或者*args以後的出現的非可變關鍵字參數 20 VAR_KEYWORD,可變關鍵字參數,對應**kwargs 21 """ 22 23 def add(x, y:int=7, *args, z, t=10,**kwargs) -> int: 24 return x + y 25 26 sig = inspect.signature(add) 27 print(sig) 28 print('params : ', sig.parameters) # 有序字典 29 print('return : ', sig.return_annotation) 30 print("*" * 20 + "我是分割線" + "*" * 20) 31 32 for i, item in enumerate(sig.parameters.items()): 33 name, param = item 34 print(i+1, name, param.annotation, param.kind, param.default) 35 print(param.default is param.empty, end='\n\n') 36 37 38 39 #以上代碼執行結果以下: 40 (x, y:int=7, *args, z, t=10, **kwargs) -> int 41 params : OrderedDict([('x', <Parameter "x">), ('y', <Parameter "y:int=7">), ('args', <Parameter "*args">), ('z', <Parameter "z">), ('t', <Parameter "t=10">), ('kwargs', <Parameter "**kwargs">)]) 42 return : <class 'int'> 43 ********************我是分割線******************** 44 1 x <class 'inspect._empty'> POSITIONAL_OR_KEYWORD <class 'inspect._empty'> 45 True 46 47 2 y <class 'int'> POSITIONAL_OR_KEYWORD 7 48 False 49 50 3 args <class 'inspect._empty'> VAR_POSITIONAL <class 'inspect._empty'> 51 True 52 53 4 z <class 'inspect._empty'> KEYWORD_ONLY <class 'inspect._empty'> 54 True 55 56 5 t <class 'inspect._empty'> KEYWORD_ONLY 10 57 False 58 59 6 kwargs <class 'inspect._empty'> VAR_KEYWORD <class 'inspect._empty'> 60 True
3>.小試牛刀
有函數以下 def add(x, y:int=7) -> int: return x + y 請檢查用戶輸入是否符合參數註解的要求? 思路 調用時,判斷用戶輸入的實參是否符合要求 調用時,用戶感受上仍是在調用add函數 對用戶輸入的數據和聲明的類型進行對比,若是不符合,提示用戶
1 #!/usr/bin/env python 2 #_*_coding:utf-8_*_ 3 #@author :yinzhengjie 4 #blog:http://www.cnblogs.com/yinzhengjie/tag/python%E8%87%AA%E5%8A%A8%E5%8C%96%E8%BF%90%E7%BB%B4%E4%B9%8B%E8%B7%AF/ 5 #EMAIL:y1053419035@qq.com 6 7 import inspect 8 9 def check(fn): 10 def wrapper(*args, **kwargs): 11 sig = inspect.signature(fn) 12 params = sig.parameters 13 values = list(params.values()) 14 for i,p in enumerate(args): 15 param = values[i] 16 if param.annotation is not param.empty and not isinstance(p, param.annotation): 17 print(p,'!==',values[i].annotation) 18 for k,v in kwargs.items(): 19 if params[k].annotation is not inspect._empty and not isinstance(v, params[k].annotation): 20 print(k,v,'!===',params[k].annotation) 21 return fn(*args, **kwargs) 22 return wrapper 23 24 @check 25 def add(x, y:int=7) -> int: #咱們要求第二個參數必須是int類型,而且返回值類型也爲int 26 return x + y 27 28 print(add(2,1)) 29 print(add(20,y=10)) 30 print(add(y=100,x=200)) 31 print(add("Yin","zhengjie")) #咱們在實際傳參時故意不按照要求傳參,發現會有相應的提示信息 32 33 34 35 #以上代碼執行結果以下: 36 3 37 30 38 300 39 zhengjie !== <class 'int'> 40 Yinzhengjie