1、对函数的参数进行类型注解
2、对函数的返回值进行类型注解
3、只对函数参数做一个辅助说明,并不对函数参数进行类型检查
4、提供给第三方工具,做代码分析,发现隐藏BUG
5、函数注解的信息,保存在__annotations__属性中
def add(x: int, y: int, *args, **kwargs) -> int:
ret = x + y
return ret
print(add.__annotations__)
out:
{'y': , 'return': , 'x': } # 无序字典
Python 3.6引入
变量注解: i: int = 3
业务应用:
函数参数的检查,一定是要函数外
函数应作为参数,传入到检查函数中
检查函数拿到函数传入的实际参数,与形参声明对比
__annotations__属性是一个字典,其中包括返回值类型的声明
假设要做位置参数的判断,无法和字典中的声明对应,要使用inspect模块
inspect模块
提供获取对象信息的函数,可以检查函数的类、类型检查
signature(callable),获取签名
签名包含了一个函数的信息,包括函数名,参数类型,它所在的类和名称空间及其他信息
Parameter对象
1、保存在元组中,是只读的
2、name,参数的名字
3、annotation,参数的注解,可能没有定义
4、default,参数的缺省值,可能没有定义
5、empty,特殊的类,用来标记default属性或者注解annotation属性的空值
6、kind,实参如何绑定到形参,就是形参的类型
POSITIONAL_ONLY,值必须是位置参数提供,Python没有实现,因为也是通过关键字传参
POSITIONAL_OR_KEYWORD,值可以作为关键字或者位置参数提供
VAR_POSITIONAL,可变位置参数,对应*args
KEYWORD_ONLY,keyword-only参数,对应*,或者*args后出现的非可变关键字参数
VAR_KEYWORD,可变关键字参数,对应**kwargs
import inspect
def add(x: int, y: int, *args, **kwargs) -> int:
return x + y
sig = inspect.signature(add)
print(1, sig)
print(2, 'params : ', sig.parameters) # OrderedDict
print(3, 'return : ', sig.return_annotation)
print(4, sig.parameters['y'])
print(5, sig.parameters['x'].annotation)
print(6, sig.parameters['args'])
print(7, sig.parameters['args'].annotation)
print(8, sig.parameters['kwargs'])
print(9, sig.parameters['kwargs'].annotation)
print(inspect.isfunction(add)) # 是否是函数
print(inspect.ismethod(add)) # 是否是类的方法
print(inspect.isgenerator(add)) # 是否是生成器对象
print(inspect.isgeneratorfunction(add)) # 是否是生成器函数
print(inspect.isclass(add)) # 是否是类
print(inspect.ismodule(inspect)) # 是否是模块
print(inspect.isbuiltin(print)) # 是否是内建对象
out:
1 (x:int, y:int, *args, **kwargs) -> int
2 params : OrderedDict([('x', ), ('y', ), ('args', ), ('kwargs', )])
3 return :
4 y:int
5
6 *args
7
8 **kwargs
9
True
False
False
False
False
True
True
import inspect
def add(x, y: int=7, *args, z, t=10, **kwargs) -> int:
return x + y
sig = inspect.signature(add)
print(sig)
print('params : ', sig.parameters)
print('return : ', sig.return_annotation)
print('~~~~~~~~~~~~~~~~')
for i, item in enumerate(sig.parameters.items()):
print(item)
name, param = item
print(i+1, name, param, param.annotation, param.kind, param.default)
print(param.default is param.empty, end='\n\n')
out:
(x, y:int=7, *args, z, t=10, **kwargs) -> int
params : OrderedDict([('x', ), ('y', ), ('args', ), ('z', ), ('t', ), ('kwargs', )])
return :
~~~~~~~~~~~~~~~~
('x', )
1 x x POSITIONAL_OR_KEYWORD
True
('y', )
2 y y:int=7 POSITIONAL_OR_KEYWORD 7
False
('args', )
3 args *args VAR_POSITIONAL
True
('z', )
4 z z KEYWORD_ONLY
True
('t', )
5 t t=10 KEYWORD_ONLY 10
False
('kwargs', )
6 kwargs **kwargs VAR_KEYWORD
True
业务应用:
参数有注解就要求实参类型和声明应该一致
import inspect
def check(fn):
def wrapper(*args, **kwargs):
print(args, kwargs)
sig = inspect.signature(fn) # 签名
params = sig.parameters # 有序字典
values = list(params.values())
print(values)
# 位置参数处理
for i, p in enumerate(args):
print(i, p)
print('===') if isinstance(p, values[i].annotation) or values[i].annotation is values[i].empty else print('xxx')
print('##', values[i].annotation)
# 关键字参数处理
for k, v in kwargs.items():
print(k, v)
print('====') if isinstance(v, params[k].annotation) else print('xxxx')
print('###', params[k].annotation)
return fn(*args, **kwargs)
return wrapper
@check
def add(x, y: int=7) -> int: # 业务函数
return x + y
print(add(5, 7))
print(add(y=4, x=9))
Out:
[, ]
0 5
===
##
1 7
===
##
12
[, ]
y 4
====
###
x 9
xxxx
###
13
out:
(5, 7) {}
[, ]
0 5
xxx
##
1 7
===
##
12
() {'x': 9, 'y': 4}
[, ]
x 9
xxxx
###
y 4
====
###
13