python的mag模块_Python全栈-magedu-2018-笔记22

第十五章 - Python 类型注解

函数定义的弊端

Python是动态语言,变量随时可以被赋值,且能赋值为不同的类型

Python不是静态编译型语言,变量类型是在运行器决定的

动态语言很灵活,但是这种特性也是弊端

def add(x, y):

return x + y

print(add(4, 5))

print(add('hello', 'world'))

add(4, 'hello') #

难发现:由于不做任何类型检查,直到运行期问题才显现出来,或者线上运行时才能暴露出问题

难使用:函数的使用者看到函数的时候,并不知道你的函数的设计,并不知道应该传入什么类型的数据

函数定义的弊端

如何解决这种动态语言定义的弊端呢?

增加文档Documentation String

这只是一个惯例,不是强制标准,不能要求程序员一定为函数提供说明文档

函数定义更新了,文档未必同步更新

def add(x, y):

'''

:param x: int

:param y: int

:return: int

'''

return x + y

print(help(add))

函数注解Function Annotations

如果解决这种动态语言定义的弊端呢?

函数注解

def add(x:int , y:int) -> int :

'''

:param x: int

:param y: int

:return: int

'''

return x + y

print(help(add))

print(add(4, 5))

print(add('mag', 'edu'))

函数注解Function Annotations

函数注解

Python 3.5引入

对函数的参数进行类型注解

对函数的返回值进行类型注解

只对函数参数做一个辅助的说明,并不对函数参数进行类型检查

提供给第三方工具,做代码分析,发现隐藏的bug

函数注解的信息,保存在__annotations__属性中

add.__annotations__

{'x': , 'y': , 'return': }

变量注解

Python 3.6引入

i : int = 3

业务应用

函数参数类型检查

思路

函数参数的检查,一定是在函数外

函数应该作为参数,传入到检查函数中

检查函数拿到函数传入的实际参数,与形参声明对比

__annotations__属性是一个字典,其中包括返回值类型的声明。假设要做位置参数的判断,无法和字典中的声明对应。使用inspect模块

inspet模块

提供获取对象信息的函数,可以检查函数和类、类型检查

inspect模块

signature(callable),获取签名(函数签名包含了一个函数的信息,包括函数名、它的参数类型、它所在的类和名称空间及其他信息)

import inspect

def add(x:int, y:int, *args,**kwargs) -> int:

return x + y

sig = inspect.signature(add)

print(sig, type(sig)) # 函数签名

print('params : ', sig.parameters) # OrderedDict

print('return : ', sig.return_annotation)

print(sig.parameters['y'], type(sig.parameters['y']))

print(sig.parameters['x'].annotation)

print(sig.parameters['args'])

print(sig.parameters['args'].annotation)

print(sig.parameters['kwargs'])

print(sig.parameters['kwargs'].annotation)

inspect模块

inspect.isfunction(add),是否是函数

inspect.ismethod(add)),是否是类的方法

inspect.isgenerator(add)),是否是生成器对象

inspect.isgeneratorfunction(add)),是否是生成器函数

inspect.isclass(add)),是否是类

inspect.ismodule(inspect)),是否是模块

inspect.isbuiltin(print)),是否是内建对象

还有很多is函数,需要的时候查阅inspect模块帮助

inspect模块

Parameter对象

保存在元组中,是只读的

name,参数的名字

annotation,参数的注解,可能没有定义

default,参数的缺省值,可能没有定义

empty,特殊的类,用来标记default属性或者注释annotation属性的空值

kind,实参如何绑定到形参,就是形参的类型

POSITIONAL_ONLY,值必须是位置参数提供

POSITIONAL_OR_KEYWORD,值可以作为关键字或者位置参数提供

VAR_POSITIONAL,可变位置参数,对应*args

KEYWORD_ONLY,keyword-only参数,对应*或者*args之后的出现的非可变关键字参数

VAR_KEYWORD,可变关键字参数,对应**kwargs

inspect模块

举例

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()):

name, param = item

print(i+1, name, param.annotation, param.kind, param.default)

print(param.default is param.empty, end='\n\n')

业务应用

有函数如下

def add(x, y:int=7) -> int:

return x + y

请检查用户输入是否符合参数注解的要求?

业务应用

有函数如下

def add(x, y:int=7) -> int:

return x + y

请检查用户输入是否符合参数注解的要求?

思路

调用时,判断用户输入的实参是否符合要求

调用时,用户感觉上还是在调用add函数

对用户输入的数据和声明的类型进行对比,如果不符合,提示用户

业务应用

import inspect

def add(x, y:int=7) -> int:

return x + y

def check(fn):

def wrapper(*args, **kwargs):

sig = inspect.signature(fn)

params = sig.parameters

values = list(params.values())

for i,p in enumerate(args):

if isinstance(p, values[i].annotation): # 实参和形参声明一致

print('')

for k,v in kwargs.items():

if isinstance(v, params[k].annotation): # 实参和形参声明一致

print('=')

return fn(*args, **kwargs)

return wrapp

调用测试

check(add)(20,10)

check(add)(20,y=10)

check(add)(y=10,x=20)

业务需求是参数有注解就要求实参类型和声明应该一致,没有注解的参数不比较,如何修改代码?

业务应用

import inspect

def check(fn):

def wrapper(*args, **kwargs):

sig = inspect.signature(fn)

params = sig.parameters

values = list(params.values())

for i,p in enumerate(args):

param = values[i]

if param.annotation is not param.empty and not isinstance(p, param.annotation):

print(p,'!',values[i].annotation)

for k,v in kwargs.items():

if params[k].annotation is not inspect._empty and not isinstance(v, params[k].annotation):

print(k,v,'!=',params[k].annotation)

return fn(*args, **kwargs)

return wrapper

@check

def add(x, y:int=7) -> int:

return x + y

调用测试

add(20,10)

add(20,y=10)

add(y=10,x=20)

最后

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值