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

fed*_*qui 62 python annotations type-hinting python-3.x python-3.6

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] = {}
Run Code Online (Sandbox Code Playgroud)

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

因此,根据我的阅读,它们是来自Python 3.5的类型提示的一部分,在Python 3.5中的什么是类型提示中有所描述.

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

Jim*_*ard 43

什么是变量注释?

变量注释只是注释的下一步# type,因为它们被定义为PEP 484; PEP 526相应部分强调了这一变化背后的基本原理.

所以,而不是暗示类型:

primes = []  # type: List[int]
Run Code Online (Sandbox Code Playgroud)

引入新语法以允许使用表单赋值直接注释类型:

primes: List[int] = []
Run Code Online (Sandbox Code Playgroud)

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

它带来了什么变化?

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

annotated_assignment_stmt ::=  augtarget ":" expression ["=" expression]
Run Code Online (Sandbox Code Playgroud)

所以有问题的例子:

   primes: List[int] = [ ]
#    ^        ^         ^
#  augtarget  |         |
#         expression    |
#                  expression (optionally initialize to empty list)
Run Code Online (Sandbox Code Playgroud)

还引入了其他更改以及新语法; 模块和类现在具有一个__annotations__属性(如PEP 3107之后的函数 - 函数注释),其中附加了类型元数据:

from typing import get_type_hints  # grabs __annotations__
Run Code Online (Sandbox Code Playgroud)

现在__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]}
Run Code Online (Sandbox Code Playgroud)

captain目前不会显示,get_type_hints因为get_type_hints只返回模块上也可以访问的类型; 即,它首先需要一个值:

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

使用print(__annotations__)会显示,'captain': <class 'str'>但你真的不应该__annotations__直接访问.

同样,对于类:

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

其中a ChainMap用于获取给定类(位于第一个映射中)的注释以及在其中找到的基类中定义的所有注释mro(对应的映射{}).

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

我会被迫使用它吗?

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

  • 随着 [PEP 585](https://www.python.org/dev/peps/pep-0585/) 的引入,Python 3.9+ 中的情况发生了一些变化。这将您的示例更改为“primes: list[int] = []”或更简单的“primes = list[int]()”。 (3认同)

Mar*_*ers 36

之间的所有内容:=是一种类型的提示,所以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__` 属性除外)? (2认同)
  • @iBug:注释是机器可读的注释,只要注释是人类可读的注释。:-) (2认同)