什么是Python 3.6中的变量注释?


83

Python 3.6即将发布。PEP 494-Python 3.6发布时间表提到了12月底,所以我仔细研究了Python 3.6的新增功能,看看他们提到了变量注释

PEP 484引入了功能参数的类型注释(也称为类型提示)的标准。该PEP向Python添加了语法,以注释变量的类型,包括类变量和实例变量:

primes: List[int] = []

captain: str  # Note: no initial value!

class Starship:
     stats: Dict[str, int] = {}

就像函数注释一样,Python解释器不会在变量注释中附加任何特殊含义,而仅将它们存储在__annotations__类或模块的特殊属性中。与静态类型语言中的变量声明相反,注释语法的目的是提供一种通过抽象语法树和__annotations__属性为第三方工具和库指定结构化类型元数据的简便方法。

因此,根据我的阅读,它们是来自Python 3.5的类型提示的一部分,如Python 3.5中的类型提示中所述

我遵循captain: strclass Starship示例,但不确定最后一个示例:如何primes: List[int] = []解释?它是否定义了一个只允许整数的空列表?


9
类型提示进行任何类型检查。primes: List[int] = []只是一个空列表primes = []。所不同的是,你声称primes 是为了只包含intS和第三方应用程序可能键入检查程序,以验证这种说法,但是当你运行任何Python解释这只是一样写代码primes = [],从而做primes: List[int] = []; primes.append("string")仍然是有效。
巴库里

2
@Bakuriu是的,很好。正如Jim Fasarakis-Hilliard在他对“ Python 3.5中的类型提示是什么”的回答中所描述的那样,为什么要键入类型提示帮助类型检查器,帮助编写文档并帮助IDE开发更准确,更强大的工具。摘自PEP 526-变量注释的语法Python仍将是一种动态类型化的语言,即使按惯例,作者也不希望使类型提示成为强制性的
fedorqui'SO stop harm''Oct

1
这回答了你的问题了吗?Python 3.5中的类型提示是什么?
AMC

Answers:


46

:和之间的所有内容都是=类型提示,因此primes确实定义为List[int],并且最初设置为一个空列表(并且stats最初是一个空字典,定义为Dict[str, int])。

List[int]并且Dict[str, int]不是下一个语法的一部分,但是,这些已经在Python 3.5键入提示PEP中定义。3.6 PEP 526 –变量注释语法提案定义了将相同的提示附加到变量的语法。在您只能将类型提示附加到带有注释的变量之前(例如primes = [] # List[int])。

这两个ListDict通用类型,这表明你有特定的(具体)内容的列表或字典映射。

对于List,只有一个“参数”([...]语法中的元素),即列表中每个元素的类型。对于Dict,第一个参数是键类型,第二个参数是值类型。因此,列表中的所有primes都是整数,而字典中的所有键值对stats都是(str, int)将字符串映射为整数的对。

请参阅typing.Listtyping.Dict定义,有关泛型部分以及PEP 483 –类型提示理论

就像函数上的类型提示一样,它们的使用是可选的,并且也被认为是注释(只要有一个对象可以附加这些注释,那么模块中的全局变量和类的属性,而不是函数的局部变量)就可以通过__annotations__属性进行内省。您可以将任意信息附加到这些批注中,而不仅限于类型提示信息。

您可能需要阅读完整的建议;它包含了新语法之外的一些附加功能;例如,它指定了何时评估此类注释,如何进行内部检查以及如何将某些内容声明为类属性与实例属性。


我是否可以将类型提示视为一种“机器可读”的注释,因为它们不影响代码的运行方式(obj.__annotations__属性除外)?
iBug

1
@iBug:注释是机器可读的注释,因此注释无论如何都是人类可读的注释。:-)
马丁·彼得

56

什么是变量注释?

变量注释只是注释中的下一步# type,因为它们是在PEP 484;中定义的。PEP 526相应部分重点介绍了此更改的原理。

因此,与其使用以下类型来提示类型:

primes = []  # type: List[int]

引入新的语法,以允许使用形式的赋值直接注释类型:

primes: List[int] = []

正如@Martijn指出的那样,typing它使用可用的类型并将其初始化为空列表来表示整数列表。

它带来什么变化?

引入的第一个更改是新的语法,该语法使您可以使用类型来注释名称,该名称可以在:字符后单独添加,也可以选择注释,同时还为其分配值:

annotated_assignment_stmt ::=  augtarget ":" expression ["=" expression]

因此,有问题的示例:

   primes: List[int] = [ ]
#    ^        ^         ^
#  augtarget  |         |
#         expression    |
#                  expression (optionally initialize to empty list)

还引入了其他更改以及新语法。模块和类现在具有__annotations__属性(就像自PEP 3107-Function Annotations以来的功能一样),该属性中附加了类型元数据:

from typing import get_type_hints  # grabs __annotations__

现在__main__.__annotations__保存声明的类型:

>>> from typing import List, get_type_hints
>>> primes: List[int] = []
>>> captain: str
>>> import __main__
>>> get_type_hints(__main__)
{'primes': typing.List<~T>[int]}

captain当前不会显示出来,get_type_hints因为get_type_hints仅返回还可以在模块上访问的类型;即,它首先需要一个值:

>>> captain = "Picard"
>>> get_type_hints(__main__)
{'primes': typing.List<~T>[int], 'captain': <class 'str'>}

使用print(__annotations__)将显示,'captain': <class 'str'>但您实际上不应该__annotations__直接访问。

同样,对于类:

>>> get_type_hints(Starship)
ChainMap({'stats': typing.Dict<~KT, ~VT>[str, int]}, {})

其中aChainMap用于获取给定类的注释(位于第一个映射中)和在其基类中找到的所有基类中定义的所有注释mro{}对象的后续映射)。

与新语法一起,ClassVar添加了新类型来表示类变量。是的,stats在您的示例中,实际上是一个实例变量,而不是ClassVar

我会被迫使用吗?

与来自中的类型提示一样PEP 484,它们完全是可选的,并且主要用于类型检查工具(以及根据此信息可以构建的其他任何内容)。当发布稳定版本的Python 3.6时,它将是临时的,因此将来可能会添加一些小的调整。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.