如何在 python 3.6 中使用类型提示?

Posted

技术标签:

【中文标题】如何在 python 3.6 中使用类型提示?【英文标题】:How to use type hints in python 3.6? 【发布时间】:2017-05-12 10:13:26 【问题描述】:

我注意到 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 之后。 Pycharm 检测到类型错误并给了我一个警告,但它并不明显并且没有显示在输出控制台中,我害怕有时我会错过它。我想要以下效果:

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

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

【问题讨论】:

mypy 已经支持 Python 3.6 变量注释。 相关的,如果不是欺骗:What are Type Hints in Python 3.5 和 What are variable annotations in Python 3.6? 为了简短起见:类型注释并不意味着强制类型。语言继续是动态类型的。 【参考方案1】:

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

Python 不可能为你做这件事;您可以使用mypy 进行类型检查(PyCharms 内置检查器也应该这样做)。除此之外,mypy不限制您只能输入 cmets # type List[str],您可以像在 Python 3.6 中一样使用变量注释,因此 a: List[str] 也同样适用。 p>

按原样使用mypy,因为版本是新的,您需要安装typed_ast 并使用--fast-parser--python-version 3.6 as documented in mypy's docs 执行mypy。这可能很快就会改变,但现在你需要他们让它顺利运行

更新:现在不需要--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 类型提示的许多其他答案中所述mypyPyCharms 的类型检查器是执行验证的,不是 Python 本身。 Python 目前不使用此信息,它仅将其存储为元数据并在执行过程中忽略它。

【讨论】:

【参考方案2】:

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

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

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

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

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

尽管可以预期,未来版本的 Python 可能会在 Python 运行时本身上加入编译时类型检查 - 很可能是通过可选的命令行开关。 (我认为它永远不会成为默认值 - 至少不会破坏构建 - 也许可以将其设为默认值以发出警告)

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

【讨论】:

【参考方案3】:

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

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

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

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

【讨论】:

以上是关于如何在 python 3.6 中使用类型提示?的主要内容,如果未能解决你的问题,请参考以下文章

Python 3.6 泛型类型提示

Python 3.6无法通过命令提示符运行

如何通过 virtualenv 在 Amazon 的 Elastic Beanstalk 上使用最新版本的 python (3.6)

在Cakephp 3.6中如何获取图像的大小和类型以通过表单发送?

Python:如何覆盖子类中实例属性的类型提示?

详解如何在 Linux 中安装最新的 Python 3.6 版本