参考资料:
https://blog.csdn.net/weixin_40908748/article/details/106252884
https://www.python.org/dev/peps/pep-0484/
https://www.jetbrains.com/help/pycharm/stubs.html
写这篇文章的原因是我在网上下载的项目中看到了.pyi文件,但是寻找了很多资料才对这些个概念(存根文件、类型检查)有了一个直观的印象。这篇随笔的目的是用最短的篇幅让你理解这些概念!
首先我介绍几个论断:
1. PEP484
首先PEP是Python社区使用的规范化文档(就好像IETF用的rtf),PEP484这个文档是对type hint作规范化的文档!它规范化了type hint所需的语法用法...比如如果你关心stub存根文件是怎么做规范化的,你可以看参考资料2。
2.type checker
PEP484只是一个规范化的文档,没有给出具体的hint软件。事实上有一个内置模块叫typing,但它是让你用规范的语法写type hint的。不是一个类型检查器!!!
问:有哪些类型检查器可用?答:Pycharm内置有type checker,并且可用,明确支持stub file。mypy这个软件明确支持stub。其他的hinter,pyhinter等...我测试了一下,在vscode中效果不理想。
3.来看看,一个最简单的type hint,一个最简单的stub file长什么样
一个最简单的带annotation(type hint)的函数定义:
def greeting(name: str) -> str: return "Hello" + name
一个最简单的stub file:
def greeting(name: str) -> str: ...
4.后缀为.pyi的stub存根文件的作用:
当没有存根文件,同时在函数定义的时候不加annotation的情况:
可见,由于python没有内置静态类型检查,只有运行时的动态检查。Pycharm给这个在运行时会出错的文件打了小对勾。
但是,当我们在同一个文件夹下写一个stub file之后呢?
有了stub file的指引,有了Pycharm内置的type checker做静态检查驱动。在代码没有运行的时候就检查出来了类型错误!!这在维护大型的项目的时候是非常有用的。
看了上面这几个论断,你是不是对相关的概念有了一个初步的理解?下面我们自己动手做一个实验,目的是在一个文件夹中写module并定义函数,在另一个文件夹中统一存放存根文件(因为方便管理呀,并且能够多次使用实现复用!)而且我们已经知道了,type checker这个活不是必须的,可以由mypy,Pycharm来干,那么我们想找到指导当然要寻求这些工具的指导。比如:Pycharm的stub说明。https://www.jetbrains.com/help/pycharm/stubs.html#create-stub-external,废话不多说,动手做一做。
第一步:
生成代码文件和存根文件,其中存根文件放到一个统一的文件夹中统一存放。
第二步:
按照Pycharm文档中的指引,将存根文件的目录添加到PATH中,一定要注意文件名要对应上。(在IDE中可以方便的配置,当真正工程上应用的话可能就要手动添加PATH了,但要注意:hints是给人看的,类型检查也是给人警告的,不能脱离应用)
Reuse stubs
You can make your stubs accessible for your other PyCharm projects.
-
Click the Project Interpreter selector in the Status Bar and select
-
In the Project Interpreter dialog, click and select
-
In the Interpreter paths dialog, click to add the new path record:
-
Inspect your project: the directory with the stub files is now marked as a library root.
Any time you will use this project interpreter to work with other projects, this stub library will be accessible through the path you have just added.
第三步:
看一下结果,发现两个module文件都找到了对应的存根。其中在最左边出现了 * ,点击的话可以在实现以及存根中跳转。