什么是变量注解?

What are variable annotations?

Python 3.6即将发布。 PEP 494 -- Python 3.6 Release Schedule mentions the end of December, so I went through What's New in Python 3.6 看到他们提到了 变量注释 :

PEP 484 introduced standard for type annotations of function parameters, a.k.a. type hints. This PEP adds syntax to Python for annotating the types of variables including class variables and instance variables:

primes: List[int] = []

captain: str  # Note: no initial value!

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

Just as for function annotations, the Python interpreter does not attach any particular meaning to variable annotations and only stores them in a special attribute __annotations__ of a class or module. In contrast to variable declarations in statically typed languages, the goal of annotation syntax is to provide an easy way to specify structured type metadata for third party tools and libraries via the abstract syntax tree and the __annotations__ attribute.

因此,根据我的阅读,它们是来自 Python 3.5 的类型提示的一部分,在 .

中进行了描述

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

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

List[int]Dict[str, int] 不是下一个语法的一部分,但是,它们已经在 Python 3.5 打字提示 PEP 中定义。 3.6 PEP 526 – Syntax for Variable Annotations 提案 only 定义了将相同提示附加到变量的语法;在您只能将类型提示附加到带有注释的变量之前(例如 primes = [] # List[int])。

ListDict都是Generic类型,表示你有一个列表或字典映射特定(具体)内容。

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

参见typing.List and typing.Dict definitions, the section on Generics, as well as PEP 483 – The Theory of Type Hints

就像函数的类型提示一样,它们的使用是可选的,也被认为是注释(前提是有一个对象可以附加这些,所以模块中的全局变量和 classes,但不是函数中的局部变量),您可以通过 __annotations__ 属性进行自省。您可以将任意信息附加到这些注释,您并不严格限于类型提示信息。

您可能想阅读 full proposal;它包含一些超越新语法的附加功能;例如,它指定何时评估此类注释、如何内省它们以及如何将某些内容声明为 class 属性与实例属性。

What are variable annotations?

变量注释只是 # type 注释的下一步,正如它们在 PEP 484 中定义的那样; respective section of PEP 526 中突出显示了此更改背后的基本原理。

因此,与其提示类型:

primes = []  # type: List[int]

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

primes: List[int] = []

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

What changes does it bring?

引入的第一个更改是 new syntax,它允许您使用类型注释名称,可以在 : 字符之后单独注释,也可以选择注释同时为其分配值:

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

所以有问题的例子:

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

新语法还引入了其他更改;模块和 classes 现在有一个 __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 只有 returns 类型也可以在模块上访问;即,它首先需要一个值:

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

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

同样,对于 classes:

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

其中 ChainMap 用于获取给定 class 的注释(位于第一个映射中)以及在其 [ 中找到的基础 classes 中定义的所有注释=31=](后续映射,对象为 {})。

除了新语法外,还添加了一个新的 ClassVar 类型来表示 class 变量。是的,您示例中的 stats 实际上是一个 实例变量 ,而不是 ClassVar.

Will I be forced to use it?

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