想要开发一个供 Python 使用的静态类型检查项目 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
LeeReamond
V2EX    Python

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

  •  
  •   LeeReamond 2021-01-27 19:31:50 +08:00 2053 次点击
    这是一个创建于 1718 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

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

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

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

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

    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 运行的实例进行某种替换,以实现执行前和执行后的输入输出检查。我个人技术比较低微,不知道这种接管有没有可能实现,简单想了一下没什么好的办法,各位提提意见。

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

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

    pytest-mypy 也有
    不要总觉得没人做过,就马上要造轮子,先说说已有的方案为何不满足
    LeeReamond
        6
    LeeReamond  
    OP
       2021-01-29 02:07:07 +08:00   1
    @frostming mypy 的 pycharm 插件很好用,但是 runtime 我觉得很糟糕,经常卡死,异常又怪。不过刚才试了一下,之前没试过的,runtime 确实是支持 PEP563,这样说来也堪用了
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2616 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 23ms UTC 06:07 PVG 14:07 LAX 23:07 JFK 02:07
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86