python 类型注解 list,Python类型注解
发布日期:2021-06-24 13:15:16 浏览次数:2 分类:技术文章

本文共 5500 字,大约阅读时间需要 18 分钟。

form: none; line-height: 1.8; text-indent: 2em; letter-spacing: normal; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Ubuntu, "Helvetica Neue", Helvetica, Arial, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", "Source Han Sans CN", sans-serif; font-size: 16px; font-style: normal; font-weight: 4.0; word-spacing: 0px; white-space: normal; box-sizing: border-box; orphans: 2; widows: 2; background-color: rgb(255, 255, 255); font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">

函数定义的弊端

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

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

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

def add(x, y):return x + yprint(add(4, 5))print(add(‘hello’, ‘world’))#add(4, ‘hello’)

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

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

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

增加文档Documentation String p

这只是一个惯例,不是强制标准,不能要求程序员一定为函数提供说明文档 p 函数定义更新了,文档未必同步更新

def add(x, y):”’:paramx: int:paramy: int:return: int”’return x + yprint(help(add))

print(add(4,5))print(add(‘mag’,’edu’))

函数注解 p Python 3.5引入

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

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

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

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

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

函数参数类型检查

思路

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

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

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

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

inspet模块

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

Inspect模块

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

import inspectdef add(x:int,y:int,*args,**kwargs)->int:return x + ysig = inspect.signature(add)print(sig,type(sig)) #函数签名print(‘params:’,sig.parameters)#有序字典print(‘return : ‘,sig.return_annotation)print(sig.parameters[‘x’],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.isfunction(add),是否是函数

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

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

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

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

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

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

还有很多is函数,需要的时候查阅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

举例

import inspectdef add(x:int,y:int=7,*args,z,t=10,**kwargs)->int:return x + ysig = 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 = itemprint(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 p

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

import inspectdef add(x, y:int=7) -> int:return x + ydef check(fn):def wrapper(*args, **kwargs):sig = inspect.signature(fn)params = sig.parametersvalues = 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 wrapper

import inspectdef check(fn):def wrapper(*args, **kwargs):sig = inspect.signature(fn)params = sig.parametersvalues = 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@checkdef add(x, y:int=7) -> int:return x + y

Functools模块

partial方法

偏函数,把函数部分的参数固定下来,相当于为部分的参数添加了一个固定的默认值,形成一 个新的函数并返回 p

从partial生成的新函数,是对原函数的封装

import functoolsdef add(x,y) -> int:return x + ynewadd = functools.partial(add,y=5)print(newadd(7))print(newadd(7,y=6))print(newadd(y=8,x=9))

import inspectprint(inspect.signature(newadd))

举例

import functoolsdef add(x,y,*args)-> int:print(args)return x+ynewadd = functools.partial(add,1,2,3,4)print(newadd(7))print(newadd(7,10))#print(newadd(9,10,y=20,x=26))print(newadd())

import inspectprint(inspect.signature(newadd))

import functoolsdef partial(func, *args, **keywords):def newfunc(*fargs, **fkeywords): # 包装函数newkeywords = keywords.copy()newkeywords.update(fkeywords)return func(*(args + fargs), **newkeywords)newfunc.func = func # 保留原函数newfunc.args = args # 保留原函数的位置参数newfunc.keywords = keywords # 保留原函数的关键字参数参数return newfuncdef add(x,y):return x+yfoo = partial(add,4)foo(5)

@functools.lru_cache(maxsize=128, typed=False) p

Least-recently-used装饰器。lru,最近最少使用。cache缓存p

如果maxsize设置为None,则禁用LRU功能,并且缓存可以无限制增长。当maxsize是二的幂 时,LRU功能执行得最好p

如果typed设置为True,则不同类型的函数参数将单独缓存。例如,f(3)和f(3.0)将被视为具有不 同结果的不同调用

import functoolsimport time@functools.lru_cache()def add(x,y,z=3):time.sleep(z)return x + yprint(add(4,5))print(add(4.0,5))print(add(4, 6))print(add(4, 6, 3))print(add(6, 4))print(add(4, y=6))print(add(x=4, y=6))ptint(add(y=6, x=4))

举例:打印斐波那契数列

import functools@functools.lru_cache()def add(n):if n <3:return 1return add(n-1)+add(n-2)print(add(35))

lru_cache装饰器应用

使用前提

同样的函数参数一定得到同样的结果

函数执行时间很长,且要多次执行

本质是函数调用的参数=>返回值

缺点

不支持缓存过期,key无法过期、失效p

不支持清除操作

不支持分布式,是一个单机的缓存

适用场景,单机上需要空间换时间的地方,可以用缓存来将计算变成快速的查询

01903f2303fd0ac74e96dd767b78fe22.png

转载地址:https://blog.csdn.net/weixin_33045961/article/details/116171356 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:ORACLE客户端jdbc连接测试,Oracle 客户端JDBC连接测试工具
下一篇:homestead开发php,介绍ThinkPHP开发环境之Homestead

发表评论

最新留言

路过按个爪印,很不错,赞一个!
[***.219.124.196]2024年04月15日 06时05分25秒