53

我注意到 Python 3.5 和 Python 3.6 添加了很多关于静态类型检查的功能,所以我尝试了以下代码(在 python 3.6 中,稳定版)。

from typing import List

a: List[str] = []
a.append('a')
a.append(1)
print(a)

令我惊讶的是,Python 并没有给我一个错误或警告,尽管它1被附加到list应该只包含字符串的 a 中。Pycharm检测到类型错误并给了我一个警告,但它并不明显并且没有显示在输出控制台中,我担心有时我可能会错过它。我想要以下效果:

  1. 如果很明显我使用了错误的类型,如上所示,抛出警告或错误。
  2. 如果编译器无法可靠地检查我使用的类型是对还是错,请忽略它。

那可能吗?也许mypy可以做到,但我更喜欢使用 Python-3.6 风格的类型检查(like a: List[str])而# type List[str]不是mypy. 而且我很好奇本机python 3.6中是否有一个开关来实现我上面所说的两点。

4

3 回答 3

41

类型提示完全应该被 Python 运行时忽略,并且仅由第三方工具(如 mypy 和 Pycharm 的集成检查器)检查。还有各种鲜为人知的 3rd 方工具,它们在编译时或运行时使用类型注释进行类型检查,但大多数人使用 mypy 或 Pycharm 的集成检查器 AFAIK。

事实上,我实际上怀疑类型检查是否会在可预见的未来完全集成到 Python 中——参见PEP 484(引入类型注释)和PEP 526(引入变量注释)的“非目标”部分,以及正如 Guido在这里的评论。

我个人对类型检查与 Python 更紧密地集成感到满意,但似乎整个 Python 社区还没有准备好或愿意进行这样的改变。

最新版本的 mypy 应该理解 Python 3.6 变量注释语法和注释样式语法。事实上,变量注释基本上是 Guido 最初的想法(Guido 目前是 mypy 团队的一员)——基本上,mypy 和 Python 中对类型注释的支持几乎是同时开发的。

于 2016-12-28T06:55:09.403 回答
24

那可能吗?也许 mypy 可以做到,但我更喜欢使用 Python-3.6 样式的类型检查(like a: List[str])而不是 mypy 中使用的注释样式(like # type: List[str])。而且我很好奇本机python 3.6中是否有一个开关来实现我上面所说的两点。

Python 无法为您做到这一点。您可以使用它mypy来进行类型检查(PyCharms 内置检查器也应该这样做)。除此之外,mypy不会限制您只能输入注释# type List[str],您可以像在 Python 3.6 中一样使用变量注释,因此a: List[str]效果同样好。

照原样,因为mypy版本是新的,你需要按照 mypy 的文档中的文档安装和typed_ast执行。这可能很快就会改变,但现在你需要它们让它顺利运行mypy--fast-parser--python-version 3.6

更新: --fast-parser现在--python-version 3.6不需要。

在你这样做之后,mypy 检测到你的第二个操作不兼容a: List[str]就好了。假设您的文件是tp_check.py用语句调用的:

from typing import List

a: List[str] = []
a.append('a')
a.append(1)
print(a)

mypy使用上述参数运行(您必须首先pip install -U typed_ast):

python -m mypy --fast-parser --python-version 3.6 tp_check.py

捕获错误:

tp_check.py:5: error: Argument 1 to "append" of "list" has incompatible type "int"; expected "str"

正如许多其他关于使用 Python 进行类型提示的答案中mypy所指出的那样,PyCharms 的类型检查器是执行验证的,而不是 Python 本身。Python 目前不使用此信息,它仅将其存储为元数据并在执行期间忽略它。

于 2016-12-28T10:30:08.917 回答
11

Python 中的类型注释并不意味着强制类型。任何涉及运行时静态类型依赖的事情都将意味着如此根本的变化,以至于继续将生成的语言称为“Python”甚至没有意义。

请注意,Python 的动态特性允许使用纯 Python 代码构建外部工具来执行运行时类型检查。它会使程序运行(非常)缓慢,但它可能适用于某些测试类别。

可以肯定的是 - Python 语言的基础之一是一切都是对象,并且您可以尝试在运行时对对象执行任何操作。如果对象没有符合所尝试操作的接口,它将在运行时失败。

本质上是静态类型的语言以不同的方式工作:在运行时尝试操作时,只需在对象上可用。在编译步骤中,编译器在各处为适当的对象创建空间和槽——并且,在不符合要求的情况下,会中断编译。

Python 的类型检查允许任何数量的工具准确地做到这一点:在实际运行应用程序之前的一步中断和警告(但独立于编译本身)。但是语言的性质不能改变为实际上要求对象在运行时遵守 - 在编译步骤本身的打字和中断将是人为的。

虽然,可以预期 Python 的未来版本可能会在 Python 运行时本身上合并编译时类型检查——最有可能通过可选的命令行切换。(我认为它永远不会默认 - 至少不会破坏构建 - 也许可以将其设为默认以发出警告)

因此,Python 不需要在运行时进行静态类型检查,因为它将不再是 Python。但是至少存在一种同时使用动态对象和静态类型的语言——Cython 语言,它在实践中作为 Python 超集工作。人们应该期望Cython 很快将新的类型提示语法合并为实际的类型声明。(目前它对可选的静态类型变量使用不同的语法)

于 2016-12-28T13:24:33.553 回答