Python入門篇-類型註解

              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
Parameter對象

 

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
相關文章
相關標籤/搜索