• Python入门篇-类型注解


                  Python入门篇-类型注解

                                          作者:尹正杰

    版权声明:原创作品,谢绝转载!否则将追究法律责任。

    一.函数定义的弊端

    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>.函数注解

     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 Annotations

    1>.函数注解

      Python 3.5引入
      对函数的参数进行类型注解
      对函数的返回值进行类型注解
      只对函数参数做一个辅助的说明,并不对函数参数进行类型检查
      提供给第三方工具,做代码分析,发现隐藏的bug
      函数注解的信息,保存在__annotations__属性中

    2>.变量注解

    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='
    
    ')
    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
  • 相关阅读:
    》》》oracle新建用户
    SVN(subversion )服务端和客户端的下载安装使用
    《《《 【WEB前端】零基础玩转微信小程序——在vscode(Visual Studio Code)安装easy less
    《《《 【WEB前端】零基础玩转微信小程序——新建⼩程序项⽬
    《《《 【WEB前端】零基础玩转微信小程序——新建一个项目页面
    《《《 【WEB前端】零基础玩转微信小程序中的 相关代码dome03.wxml
    cocos2dx 流光着色器
    [NCTF2019]True XML cookbook
    [BJDCTF2020]EasySearch
    [GKCTF2020]老八小超市儿
  • 原文地址:https://www.cnblogs.com/yinzhengjie/p/10971296.html
Copyright © 2020-2023  润新知