函数定义的弊端
动态语言的弊端,不能事先声明类型,赋值可以是不同的类型,只有在运行时才能发现
动态语言的灵活的特性也是弊端
为解决这些问题而使用类型注解,但也只是声明,并不能强制约束
难发现,问题只有使用时才能发现,
难使用,函数使用者并不能知道数据类型
Documentation string文档说明,def后的三引号内的内容,pychram这些工具可以帮助你创建说明,惯例,不是强制标准
函数注解Function Annotations
def add(x:int,y:int) -> int,约定,不是强制性约束
Python3.5引入
对函数进行类型注解,返回值也可以注解
并不会对参数进行类型检查
只是说明性的辅助,并不会对参数检查
提供给第三方工具,做代码分析,发现bug隐藏,例如 pychram会在类型错误时改变变量颜色
函数注解的信息,保存在 fn.__annotations__
函数的注解必不可少,
可以来类型检查,通过编译器
判断实参和形参的类型是否相同
变量注解
3.6以后的版本可以对变量注解
函数参数类型检查的思路
参数检查一定在函数外
函数作为参数传入,检查函数拿到函数的实参,与形参的声明做对比
fn.__annotations__属性是一个字典,包括返回值类型的声明,想要判断位置参数,就无法和字典对应,要引入inspect模块
inspect模块
提取获取对象信息的函数,可以检查函数的类
import.inspect
sig = inspect.signature(foo) 获取签名,函数签名包括函数的信息,函数名,参数类型,他所在空间及类和其他信息。
inspect 下有许多判断方式,例如
isfunction(add) 是否是函数,
ismethod(add) 是否是类方法
isgenerator(add) 是否是迭代器
isgeneratorfunctions(add) 是否是生成器函数
isclass(add) 是否是类
ismodule 是否是模块
isbuiltin 是否是内建函数
getdoc 获取函数文档
更多可查看inspect模块
sig.parameters 获取有序字典,包含参数类型声明,有序字典的key是形参,value是类型声明
Parameters 保存在元组中,是只读的
name 参数名字
annotations 参数注解,可能没有定义,
default 参数缺省值,可能没有定义
empty 特殊的类,用来标记default属性或者注释annotation属性的空值
kind 形参的类型
给一个函数加强功能,要求能检查用户输入是否符合参数注解的要求
def check(fn): def wrap(*args,**kwargs): sig = inspect.signature(fn)#获取签名 params = sig.parameters#获取参数注解 value = list(params.values()) for i,m in enumerate(args): param = value[m]#判断位置参数 if param.annotation is not param.empty and not isinstance(m,value[i].annotation): raise TypeError #else: #print('ok') for k,v in kwargs.items():##判断keyword参数 if params[k].annotation is not param.empty and not isinstance(v,params[k].annotation): raise TypeError #else: #print('okk') ret = fn(*args,**kwargs) return ret return wrap @check def add(x:int,y:int)->int: ret = x+y return ret add(1,y=2)