一日一技:Any与TypeVar,让IDE的自动补全更好用
摄影:产品经理
这家日料店恐怕已经倒闭了
相信有很多同学在写Python的时候,会使用类型标注来提高代码的可读性,同时还能帮助IDE实现自动补全。
假设我们现在获得了一个对象,这个对象可能是列表也可能是生成器,我写一个函数,获取它的第一个元素。代码很简单:
from typing import Iterator from contextlib import suppress class People: def __init__(self, name): self.name = name def eat(self): print(f'{self.name}正在吃饭') def walk(self): print(f'{self.name}正在走路') def get_first_element(ele_list): if isinstance(ele_list, list): return ele_list[0] if ele_list else None if isinstance(ele_list, Iterator): with suppress(Exception): value = next(ele_list) return value return None if __name__ == '__main__': kingname = People('kingname') pm = People('pm') people_list = [kingname, pm] obj = get_first_element(people_list) if obj: print(obj.)
代码写好了,但是当我获取第一个元素,想打印它里面的数据的时候,我发现我忘记了People这个类有哪些属性了,而此时PyCharm的自动补全也失效了,我不得不把代码往回翻,去寻找People定义的位置,效率非常低。如下图所示。
![](http://mdimg.wxwenku.com/getimg/ccdf080c7af7e8a10e9b88444af98393cd10cec255fea90b9d7617d808c97ceffa5dc8ab86911888bec1444e0425c422.jpg)
如果我们使用了类型标注,就能解决这个问题:
![](http://mdimg.wxwenku.com/getimg/356ed03bdc643f9448b3f6485edc229bd7215400ea846d9768da779fda76c72c221bb01603fa6e65c9b74b8c721cca5d.jpg)
这个常规用法,大家肯定都知道。
现在问题来了,我们除了 People
类,还有 Cat
类,并且列表里面的元素可能全是 People
类的实例,也可能全是 Cat
类实例,这种情况怎么办呢?
首先你遇到了第一个问题, get_first_element
的参数的类型标注怎么写?
你可能会写成这样:
def get_first_element(ele_list: Union[List[Union[People, Cat]], Iterator[Union[People, Cat]]])
那如果还有一个 Dog
类呢?
为了简化操作,你可能会用 Any
,类型,于是 get_first_element
变成了下面这样:
def get_first_element(ele_list: Union[List[Any], Iterator[Any]]) -> Optional[Any]: if isinstance(ele_list, list): return ele_list[0] if ele_list else None if isinstance(ele_list, Iterator): with suppress(Exception): value = next(ele_list) return value return None
现在你发现问题又来了,PyCharm的自动补全又坏了。因为Any是任何类型,所以在代码运行前,它其实不知道你返回的是什么东西。如下图所示:
![](http://mdimg.wxwenku.com/getimg/ccdf080c7af7e8a10e9b88444af983930547dcce784f08bdfd026eea48d05c5eeda657a435bdeb8c731a0b5ac684115c.jpg)
这种情况下,你就需要使用Python类型标注中的 泛型
了。我们知道,泛型是静态语言中的概念,Python由于使用了类型标注,也有了类型。于是也就借用了这个概念。
我们来看看怎么使用它:
from typing import TypeVar T = TypeVar('T')
注意这里的变量名 T
和TypeVar的参数 'T'
可以同时写成任意字符串,但变量名要与参数保持一致。例如:
GodType = TypeVar('GodType')
然后把T当作 Any
一样使用就可以。我们来看看效果:
![](http://mdimg.wxwenku.com/getimg/6b990ce30fa9193e296dd37902816f4b2f4d74d1963a702d4c02c747cdcb506dcaa09c1380dfca802f67cd5b03afe034.jpg)
可以看到,PyCharm又能自动补全了。使用 TypeVar
,可以告诉PyCharm,返回的类型跟传入参数中的 T
对应位置的类型保持一致。例如传入参数中, T
在 List[T]
或者 Generator[T]
中,所以返回的参数需要与列表中的元素或者生成器中的元素类型保持一致。
我们用Cat生成器来测试一下,发现也能自动补全:
![](http://mdimg.wxwenku.com/getimg/356ed03bdc643f9448b3f6485edc229be310bfb35f40f6ea47dcf1dcafa666d08a1dc68600274d94503c357c9f148c9b.jpg)
还有更厉害的,如果我的列表里面既有 Cat
的实例,又有 People
的实例怎么办?这个时候,PyCharm会直接把两个实例的可能补全都给你列出来:
![](http://mdimg.wxwenku.com/getimg/356ed03bdc643f9448b3f6485edc229bb95dffc86866eb5b68f48ad620b26e1235b1869390784e39b086ed972dc47174.jpg)
未闻 Code·知识星球开放啦!
一对一答疑爬虫相关问题
职业生涯咨询
面试经验分享
每周直播分享
......
未闻 Code·知识星球期待与你相见~
一二线大厂在职员工
十多年码龄的编程老鸟
国内外高校在读学生
中小学刚刚入门的新人
在 “未闻 Code技术交流群” 等你来!
入群方式:添加微信“mekingname”,备注“粉丝群”(谢绝广告党,非诚勿扰!)
爱点赞的人,运气都不会太差
- 长见识,让大家看看什么是垃圾代码
- 一日一技:用一个奇技淫巧把字符串转成特定类型
- 最适合小白的Python学习神器!
- 【粉丝投稿】机器马大佬的微软面经
- 统计千行代码Bug率,有没有意义?
- 一日一技:二分偏左,二分搜索在分布式系统里面也有用?
- 一日一技:使用Python翻译HTML中的文本字符串
- 一日一技:如何让自己的工具函数在Python全局可用?
- 一日一技:Any与TypeVar,让IDE的自动补全更好用
- 一日一技:用Python做游戏有多简单
- 一日一技:如何批量给PDF添加水印?
- 一日一技:抛掉JavaScript,用HTML和Python做网站
- 一个让我感到 "细思极恐" 的开源项目!
- 一日一技:FastAPI 接口限流
- 5 分钟,使用内网穿透快速实现远程手机桌面!
- Python Delorean 优秀的时间格式智能转换工具
- 写在公众号粉丝2w时
- 一日一技:协程与多进程的完美结合
- 一个 "丧心病狂" 的开源项目
- python中如何优雅的实现代码与敏感信息分离?