想要开发一个供 Python 使用的静态类型检查项目

2021-01-27 19:31:50 +08:00
 LeeReamond

不知道有没有类似项目,如果有的话请告诉我,

昨天发了个贴问了一下类型提示的循环导入问题,产生了一些发散式联想,能不能把现有的体系再升级一下做成一个自动检查项目,应该会挺有用的。

目前我司对于类型检查使用的是比较原始的方法,即手动增加装饰器,装饰器可以接管函数或方法的控制权,检查输入和输出是否符合标准。

而如果升级成框架的话,大概想了一下应该具有三种功能。

其一是类似直接引入式的用法,即可以嵌入一个通常程序中,对其中某个节点做检查,也是我们现在正在用的方法,这个技术上难度不大。

from 框架 import 类型检查

@类型检查
def func(a:int , b:str) -> None:
    ...

func()

其二是全局接管式,即通过修改 entrypoint 以命令行启动程序,替换 python3,对全局中的所有有类型标注的内容做检查。

root@vhost~# python3 main.py
替换成
root@vhost~# typecheck main.py

其三是接入 pytest,这个应该算是另外一个项目,比如做成 pytest 插件,暂不谈。

=============

这个项目的目的是在开发阶段,以及自动测试当中进行严格的类型约束,使程序在实际生产环境中关闭类型约束后仍然具有较高鲁棒性。它的好处是可以在最小侵入性的前提下(即保留 python 的设计哲学,pythoner 显然无意将 python 改变为一门静态类型语言,但可以通过掐头去尾的方式大幅提可靠性和降低维护难度)这是我个人的想法,我生产经验也不是特别丰富,如有错误各位指正。

大概思考了一下实现的困难,

其一是使用符合 PEP484 的类型提示规范,在目前的条件下,并且很可能未来版本中长期存在的一个问题是,对于包内循环导入,一些类型可能无法获得类实例,而只能获得包含类名的字符串。进行类型判断,从功能性角度讲理应可以向上递归,即如果定义输入类型为A 类,那么输入 A 类和其子类都是可以接受的,这种情况下需要进行 isinstance 判断,类实例进行这种判断很容易实现,字符串实现起来比较困难。

其二是如何引入检查的问题。用户自行使用装饰器修改函数的话可以自然地引入检查,但如果要用类似命令行启动的方式,实际上在做的是检查程序接管控制权,hack 进入程序当中,将所有 runtime 运行的实例进行某种替换,以实现执行前和执行后的输入输出检查。我个人技术比较低微,不知道这种接管有没有可能实现,简单想了一下没什么好的办法,各位提提意见。

1571 次点击
所在节点    Python
6 条回复
caviar
2021-01-27 20:23:42 +08:00
说实话没有完全看懂。
如果是静态检查的话,可以看下 https://github.com/python/mypy

如果是运行时检查的话,可以看下 https://typeguard.readthedocs.io/en/latest/userguide.html
有你说的用 decorator 的,也有用 profiler hook 的。
LeeReamond
2021-01-27 20:45:26 +08:00
@caviar mypy 用过,另外还用过一个叫 pyright 的,那个不怎么样,mypy 的 ide 检查还不错,但是感觉我这个偏运行时?我研究一下你发这个 typeguard,还有 profiler hook 是啥,没听过这个词
LeeReamond
2021-01-28 02:53:07 +08:00
大概调研了一下,目前感觉一个可行的实现思路是这样,首先 hook 模式对我来说难以理解,暂时认为不可行,相反装饰器模式很简单,可以通过修改装饰器修改 metaclass,实现对普通函数,和类内所有函数的手动标注,这样注入之后程序在所有函数的入口和出口处都有了类型检查,在自动测试中自然也一样。

之后只需要在发布的时候删除装饰器就可以了,可以写一个非常简单的状态机搞定。
shniubobo
2021-01-28 09:49:43 +08:00
见过一个框架通过 monkey patch 标准库,在 io 操作时自动 yield,来实现并发的: https://nameko.readthedocs.io/en/stable/key_concepts.html#concurrency
借鉴这种方法,或许可以实现在完全不修改代码的情况下测试,而不需要测试时写上装饰器、发布时删掉。
frostming
2021-01-28 10:26:45 +08:00
@LeeReamond 你这就是 mypy
mypy main.py 就能检查

pytest-mypy 也有
不要总觉得没人做过,就马上要造轮子,先说说已有的方案为何不满足
LeeReamond
2021-01-29 02:07:07 +08:00
@frostming mypy 的 pycharm 插件很好用,但是 runtime 我觉得很糟糕,经常卡死,异常又怪。不过刚才试了一下,之前没试过的,runtime 确实是支持 PEP563,这样说来也堪用了

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/749016

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX