类型注解本来没有,是python3.5慢慢引入的,就是为了解决动态语言的弊端
静态语言就是静态编译型语言
动态语言并不需要事现申明,这种变量是什么类型的,静态语言是必须申明,动态语言不需要申明,什么时候赋值,什么时候就定义出来,是什么类型,赋值什么类型就是什么类型,只要是合法的
动态语言并不能实现知道你的函数形参是什么类型
就比如函数add,传字符也行,传数字也可以,动态语言是根本没办法约定这个事情的,也就是用户在使用的时候根本不知道自己该写什么,就是可以从文档字符串告诉它
但是文档字符串不是一种语言的强制性约束,只是一个说明
(在运行时,要大量的操作,来判断是否参数是你所要求的),但是静态编译型语言就不需要这么做,在写函数的时候,就给你约定好,此函数的形参是什么类型,编译的时候就会给你报错了,还没运行
python如果没按照要求,编译是不会出错的,放在线上运行才会报错,但是python学习静态编译型语言,在你定义函数的时候,可以在函数的形参上标注类型,此类型不做强制性约束(但是java,c++不行,只要你标注int这样,你就只能传这样的)编译时就进行类型的校对,这是静态编译型语言的特征
动态语言是随你用,出错再说
python是动态语言,还是强类型语言,势必有弊端
好处是自由,可以适用多种类型,但是就因为适用多种类型,才导致写的程序跟你预期的不一样,静态语言就必须定义这个x,y是什么类型
python就必须扔到解释器跑起来,出错了才给你抛出异常,后知后觉的代价太高
强类型语言就不允许这两个混加
这种就属于跳出了使用范围
万一传的不符合要求,如果处理不好就整个程序都崩溃了
上线运行才出来就太晚了,代价太高,不做约束就需要用你没想到的方式做测试,才能报错
使用者你去使用也不知道返回什么类型,也不知道传什么类型,有时候很难看到函数的具体设计者是什么意思,所以很难传入一个正确的东西
所以3.5引入参数注解,3。6引入变量注解
以前就是这么写,(很多项目都是一个函数十几个版本,因为新来的不知道老的写的是什么用,没有注释,就自己写,久而久之项目可能就失控了)
上面的文档如果更新不及时,就出问题,python就在3.5更新了参数的注解。,主要是注解参数,还把函数注解了
告诉你x 是int y是int 返回值是int,就知道是做整形的加法
pyhon学习了变态编译型语言的特别,约束了参数是谁,但是python不做强制性约束,静态编译型语言是做强制性约束的,python只是告诉你,假如你声称int,就信你了
这样表示返回值是int,但是执行照样没有影响
换到pycharm来试试,第7行有颜色变化,但是notebook里没有变化,
是不做强制性约束,这些编辑器利用这个特性做了一定的检查工作,但是这种检查不是强制的,颜色改变告诉你,你没有按照约定来,但是不强制,注解是不强制的
没有return,颜色才变
是字符串,颜色就变了
a=none,就告诉你是不对的
如果把返回值参数注解去掉,就没有影响了
哪个变量加申明由你定提示你list这种类型没有add方法
这样就会报错,因为list根本没有add方法
就等于在运行的时候才会抛出异常
这样的代码如果上线,这样的数据一来,送进去不符合要求就报错了
还有个好处,先直接写x.点
改成list,加点,list该有的方法都有,所以现在推荐写的时候,把函数的参数注解加上去,不然你怎么知道加什么类型,如果是不认识库的,函数没有注解,你都不知道该怎么用
注解加上去,发现要的方法都在这
append函数返回none,就地修改返回none
pycharm提供了,你有参数注解,会替你进行简单的参数检查,文档字符串,会把参数列在下面
但是什么类型需要自己写,不过第一行写函数做什么作用
不过这叫参数注解或者函数注解
函数注解可以对函数的参数进行类型注解,对函数的返回值进行类型注解,
是个说明性的,不对形参和返回值做任何强制约束(有些类似pycharm的工具,帮我们进行类型的检查,这种也是个提醒也不是强制性的)
只对函数参数做一个辅助的说明,并不对函数参数进行类型检查
提供给第三方工具,做代码分析,发现隐藏的bug(让程序员提前发现问题)
这些函数的注解信息,放在函数对象的__annotations__属性中
查看类型,这个dict式个特殊的,明确告诉你是有顺序的
写个返回值是none,return总是在最后的
改成str
在3.6之前是不能这么写,相当于定义a的变量类型是什么
就是只做申明,至于照不照这个约定来,由你决定
但是函数传入的参数应该是某些类型,以方便你来完成功能,不应该是随便给的,不然设计的初衷是有出入的,要求大家应该使用类型,这个时候用注解就比较合适,返回值的类型也很重要,标注返回值的类型是什么将会更好,看的比较清楚
上面定义的函数你确定你要覆盖,这是一种善意的提醒
参数注解可以让你进行类型的检查的
pycharm工具是可以给我们做一些提醒的,如果送入的参数不对,做的提醒仅限于颜色不同(但是如果参数不对,让函数不能执行岂不更好)
定义时时每什么可以检查的,在你调用函数,传入实参的时候才开始检查,函数调用的时候,形参配上实参传过来的数据,然后函数开始压栈,然后局部变量开始压栈,(能否再这个时候做一些事情,我们去拦截,如果再函数调用之前拦截一下, 把参数检查一下,对不对,严重就警告,不严重就提醒你传的参数不对)
检查是一个功能,再函数调用之前做的,比如检查
** __annotations__是个普通的字典,刚好用的时候再3.6,就跟顺序相关,3.5之前时跟顺序无关的,所以要借助一个模块,inspect(体格获取对象信息的函数,可以检查函数和类,类型检查)**
形参只是一种注解,告诉它未来要这么用,真正用的时候就传入实参的时候,要跟形参注解的时候的类型要进行对比,
类型一致通过,不一致报错
使用isinstance,type()==也可以
fucntion有doc属性,annotations刚好放的时注解信息
生成器
有一大堆判断,是模块吗,是类吗,是方法吗(如果是类里面的叫method方法),是函数吗(callable可调用对象很多,不一定是函数)
是不是生成器函数,是不是生成器对象
iscoroutinfunction是不是协程函数
is coroutine是不是协程对象
能不能拿到一个签名
函数定义,里面有签名,拿到签名,
用b这个名称找定义,是个字典,返回告诉你b这个变量用的是整型
是不是生成器对象
是不是生成器函数
查看什么是签名,就是上面定义的东西
拿到参数列表
是个有序字典,3.5的annotations不是有序的,为了拿到这个参数列表,返回有序字典
**这是一个函数签名,前面就是函数申明定义的这一块,里面属于函数实现了,叫语句体,签名跟我们的形参有关,参数集合拿到字典来封装,为了保证顺序用了一个有序字典orderedDict
**
有序字典的key是字符串,但是你写的形参就不是,到最后你写的形参一定要有个名字就是字符串
这是把x变量对应的值进行转换
x表示个变量,变量的名称往往是个字符传,函数的名称打印出来也是字符串,func__name,而标识符是赋什么值就是什么类型,函数定义以后,函数对象给标识符赋值
但是标识符赋值什么类型就是什么类型
拿到参数后就可以进行检查了,应该在调用时检查,那么在调用时候怎么拦截,定义个check函数,能对函数进行检查
写成这样没用,不让人察觉到就需要用到装饰器
装饰器函数需要放在前面,因为用的时候需要已经定义好的
但是昨天的logger的例子,还需要在里面写,解决包装的函数,你是被包装函数
包装函数里面就进行类型检查
其实把这一块内容拿到上面就可以做参数检查了
通过inspect.signature获得前面,用这个方法对函数拿到一个签名
这个就是个类型
这个类型在构造的时候,需要签名列表,如果isnone就定义成什么东西,如果没有就定义这个,一般都是none进来,这样就可以拿到一个有序字典
在参数里 迭代得到之后会有两个东西,这么理解的话,是个有序的字典对它进行迭代,
拿到的时候key
自己试一下
这个参数缺省值还可以是空
实际在定义的过程中,z这块可以不写,不写相当于注解没有
但是这个空代表一个特殊的变量是需要定义的
这个参数类型有个属性是空,每一个参数有自己的名字name
有自己的缺省值default
类型kind
注解annotation
打印一下看看
x相当于没有定义注解,y定义了
0 x x(0是索引)
两套表现形式,有注解,和没注解
在运行时明确告诉你是参数类型parameter
写代码的时候就推不出来不知道你是什么类型
3.6就可以这么做
拿到3.6试一下,就有了
有些对象很复杂,查帮助都要查半天
类型就是inspect.parameter,就可以从 from inspect import parameter 从inspect模块导入parameter
用完就可以小时
参数名是x,缺省值是空的,annotation是列表,这里面位置和keyword都可以传参(positional or keyword)
这种语法脱离3.5就不支持了,建议把类型去掉,不建议部署3.5一下,不成熟
这样不行,改一下,刚才的技巧
这个不写也可以,上面的param相当于把变量已经定义过了
相当于a=1,a ,这是不会有错的,a就相当于空语句,没有什么作用
ctrl+左鼠标
就跳转了
这个之前就见过
positional_only 仅位置
positional or keyword 位置和关键字
var_positional 可变位置
keyword_only
var_keyword 可变关键字
定义参数只能使用这些东西,想怎么组合就需要符合什么语法
positional_only 仅位置传参只是定义了,但是实际用不到
通过这个模块提供的函数就可以检查函数内部的东西,
如果没有param.default缺省值就显示为空 insepect_empty
把x注解去掉
x后面的annotation也是空的了
没有值就都是inspect的空,点击一下
这是一个类型
是inspect模块下的一个类型
通过签名拿到了整个定义的形式,从里面可以去拿参数字典,这块提供的参数字典是一个有序字典,有序字典的key是参数的名称,value是个参数对象
参数对象有4个重要属性,name(名字依然是字符串),default(缺省值没有就是empty,有就看你定义什么类型)
annotation(声称叫什么类型不定义就是empty,),kind(name和kind是必须有的,只要有一个形参在,参数类型就定义下来了,但是缺省值和注解爱给不给)
缺省值申明改成100试试
申明是str但是缺省值是100,因为是不做强类型检查的
帮助文档说的很清楚,里面有什么
签名
告诉你签名类型
签名类型对象,可以调参数属性,这是个有序字典
返回值在专门的return_annotation里,annotation如果返回值没有指定不加 ->箭头就是empty
这个关注的少,主要还是看parameter
为什么返回值不指定有可能计算返回数字,但是报错就返回字符串,有时候合法返回是个字符串,不合法就返回一个none
注解都是非强制性约束,爱返回什么返回什么
在部署的时候都有基本要求,必须python用什么版本,因为低了可能库就没有,或者语法就报错
有序字典也是字典,能通过key访问
参数类型有4中类型,annotation是其中一个,name,kind,default
这两个不能定义缺省值和类型,都是empty,但是有key,(name,kind)
可以判断是什么类型
判断print是否是内建函数
这个parameter对象有,name参数名,kind形参的类型,annotation参数注解,default缺省值,empty特殊的类型
没有仅仅是位置参数的东西
name恰好是后面item的name
最好的是用装饰器
首先拿到签名
拿到签名也就是有序字典就可以对参数进行处理
灰色代表从来没使用过
导入语句可以放在代码中的任意一部分,但习惯上放在第一
因为没有return wrapper,这个wrapp现在就没人使用
改成wrapper
notebook适合测试,pycharm工具适合开发
有时候你起的名字可能跟系统库里的变量冲突了
注解int,返回也是int,最简单的函数
只要你传实参都做检查
4,5就随着这个传进来了
4.5检查,就要看你的代码对不对
遍历args参数
类型是放在value部分的,用key来找到values,key是有序的,你拿的时候item也是有序的
annotation放的是注解定义,返回的是类型,不是字符串
如果你不是annotation这个类型就跟我们声明的不一致
查看是否满足需要
拿签名,拿参数列表,是个有序字典,拿到后,把value有序地摘出来
4进来跟这个进行对比,5进来进行对比
加个ok
如果改成str,就是not,但是该怎么调用还是怎么调用
其实可以做个标记,flag本来是true,发现错误就是false,就break没必要检查了。下面if就需要做些事情了
现在可以抛出异常
如果用的是关键字传参,走的就是kwargs
这样检查就进不去了
kwargs还是需要的
有key找value部分的参数定义
key是参数名,v是参数类型(有4个属性,name,kind,default,annotation
跟上面其实是一个意思
假如现在这么写
x的类型定义和缺省值都为空
这两个是一个东西
如果不等于空且
如果参数的注解不等于空而且不符合它的要求
关键字也是一样的
执行一下
传4也是ok
数据结构在这里是大量使用
两种调用方式,写成装饰器也可以
标红的本质上是同一个东西,一个是遍历args,一个是遍历kwargs.items
这里面最麻烦的就是用位置参数怎么对应的问题,顺序一样就可以用同一个索引来比较了