Python SDK 支持可选静态类型检查

LeanCloud Python SDK 在兼容 Python 3 之后仍然不断改进,现在已经支持 Python 3.5 的最新特性「类型提示」以及通过 Mypy 对 Python 代码进行类型检查了。

首先让我们了解一下什么是类型提示。动态语言的一大优势是在声明变量时不需要去指定变量类型,程序会在运行时候解析出变量的类型,这样能够减少一部分代码量,加快程序的编写速度。然而优势有时也是劣势。虽然不声明变量类型在编写程序时能带来方便,但很多时候却会降低程序的可读性。

举个例子:

def find_the_i_th_user(index):
    response = request.put('www.leancloud/userquery/index/' + index)
    ...

从函数 find_the_i_th_user 的字面含义可以判断其参数 index 应该是一个整数型,而事实上函数体把 index 作为一个表示整数的字符串与另一个字符串相加并发送了出去。在这种情况下如果给 find_the_ith_user 传入一个整数,程序就会直接崩溃。但如果把这行代码写成以下的形式,则能让程序员在第一时间知道 index 的正确类型并可完全避免以上错误。

def find_the_i_th_user(index: str):
    response = request.put('www.leancloud/userquery/index/' + index)
    ...

或许你认为只要看一眼就知道这个参数的类型了,根本不需要多余的提示。对于小型项目来说的确如此,但对于有上万行代码的项目就困难多了。读代码的人需要翻阅好几个 module 才能追溯到某个参数的类型,并且这种低效而且痛苦的体验还容易引入 bug,因此一些大公司早已自行采取方案对大型的 Python 项目做静态类型检查了。

幸好在 2015 年 9 月发布的 Python 3.5 已经可以支持类型提示了。在函数中我们可以通过以下形式指定类型提示:

def add(a: int, b: int) -> int:
    return a + b

对于 Python 3.5 之前版本的类型提示规范和其他更复杂的用法可以参见 PEP 484

那么 Python 为何选择在 3.5 版本中加入类型提示呢?这有一段横跨了 17 年的历史。

事实上 Python 的创始人 Guido van Rossum 在 2000 年左右便试图在 Python 社区中发言,希望能给 Python 增加可选静态类型的功能,让程序员可以在 Python 代码中直接声明静态类型,然而这一建议在社区中引起了轩然大波。反对者认为这样会损害到 Python 作为动态语言的「纯洁性」,甚至有极端者表示这样可能将 Python 的未来推向静态语言。出于种种原因 Rossum 只好作罢,但他并没有死心——既然大家不能接受 Python 支持静态类型这件事,那支持类型提示总是可以吧。于是他在 2006 年提出了 PEP 3107,希望能在 Python 3 中支持函数的类型提示。不过这一提议的回应者寥寥无几,Rossum 之后便没再提起。

事情的转机出现在 2013 年。一位来自芬兰名叫 Jukka Lehtosalo 的少年远赴重洋,从欧洲来到美国的 PyCon 2013,做了一场名为《Mypy: Optional Static Typing for Python》的演讲。Jukka 在这场演讲中介绍说自己正在开发一门叫「Mypy」的 Python 方言,其最大的特点便是同时支持静态和动态类型。该想法与 Rossum 在十三年前的提议不谋而合。

而这位神秘的 Jukka Lehtosalo 是何许人呢?同 Linux 系统的作者 Linus 一样,Jukka 也来自冰天雪地的芬兰。作为世界上纬度最高的国家之一,漫长的冬天 Jukka 只能待在家中。于是他只好通过编写程序来自娱自乐。在 1996 年 Python 发布 1.4 版本时 Jukka 接触到了这门语言,并且立即成为了 Python 的拥趸,而后经过数年的工作,他熟悉了编译器的各种细节,并于 2009 年进入牛津大学攻读 PhD,而他的目标正是创造一种和 Python 类似、并且同时支持静态和动态类型的语言。

经过数年的准备和研发, Jukka 写出了能支持静态和动态类型的类型检查器,并且来到美国的 PyCon 2013 分享他的成功。通过这次大会 Jukka 和 Rossum 相遇并一拍而和,Jukka 便将 Mypy 中类型的表达定为 PEP 3107 中的形式。

和 Jukka 交谈后,Rossum 得到灵感,撰写出 PEP 483 The Theory of Type Hints。而后 Rossum 和 Jukka 一同把这篇草稿扩展成了 PEP 484 Type Hint 并在 2015 年作为 Python 3.5 的新功能发布。而这时 Mypy 经过变迁,已经将自己定位成对 Python 做静态类型检查的工具了。

值得注意的是,Python 的静态检查功能目前对 2.7 – 3.5 版本都适用,区别只是语法和依赖模块的不同。

说了那么多历史,到底该怎样使用 Mypy 来做静态检查呢?

  1. 首先需要通过 pip install mypy 下载 mypy
  2. 从 LeanCloud Python SDK 的 代码库 下载当前版本的 stubs 文件(也可以从 release 页面 下载之前对应版本的 stubs 文件。)
  3. 在命令行中执行 export MYPYPATH=/the/dir/of/stubs/file,将 MYPYPATH 环境变量设置成 stubs 所在的路径就可以了。
    比如将 Python SDK clone 到 ~/utils/python_sdk 这个目录下后,需要执行 export MYPYPATH=~/utils/python-sdk/stubs,然后在命令行中输入 mypy your_project 就可以对你的 Python 代码进行静态类型检查了(其中 your project 是你的代码所在的目录)。

当然,进行检查的部分只有 LeanCloud SDK 中的函数和目前 mypy 检查库中支持的函数,详情请查看 typeshed

如果想要配合 Pycharm 来做类型检查,只需在 Python SDK 中找到 stubs 文件,将 stubs/leancloud 中的所有 pyi 文件放置到与你的 Python SDK 代码相同的目录下,Pycharm 便会自动对你的函数调用进行静态检查了。


P.S. 目前 mypy 暂时不支持 metaclass,所以直接从 Object 的子类创建 query 会在检查中报错,忽略即可。等到 mypy 在将来支持了 metaclass,该问题就会解决。

Python SDK 支持可选静态类型检查》上有1条评论

  1. Pingback引用通告: 2016 年 7 月份 LeanCloud 更新汇总 | LeanCloud Blog

发表评论

电子邮件地址不会被公开。 必填项已用*标注