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
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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
当你的才华还撑不起你的野心的时候,你就应该静下心来学习。当你的能力还驾驭不了你的目标的时候,你就应该沉下心来历练。问问自己,想要怎样的人生。
欢迎交流学习技术交流,个人微信: "JasonYin2020"(添加时请备注来源及意图备注)
作者: 尹正杰, 博客: https://www.cnblogs.com/yinzhengjie/p/10971296.html