变量注释是什么?

128

Python 3.6即将发布。PEP 494 -- Python 3.6 Release Schedule提到将在12月底发布,因此我查看了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的类型提示的一部分,What are Type hints in Python 3.5中有描述。
我跟随了`captain: str`和`class Starship`的例子,但对于最后一个例子不确定:`primes: List[int] = []`是如何解释的? 它定义了一个允许整数的空列表吗?

16
类型提示(Type hints)并不进行任何类型检查。primes: List[int] = [] 只是一个空列表,就像 primes = [] 一样。不同之处在于,你声称 primes 应该只包含 int 类型的元素,第三方应用程序可能会对你的程序进行类型检查以验证这个声明,但在任何 python 解释器中运行代码时,这与编写 primes = [] 是一样的,因此执行 primes: List[int] = []; primes.append("string") 仍然是有效的。 - Bakuriu
2
@Bakuriu,非常好的观点。正如Jim Fasarakis-Hilliard在他回答Python 3.5中的类型提示是什么中所描述的那样,为什么使用类型提示 → _有助于类型检查器、帮助文档编写和帮助IDE开发更准确、更强大的工具_。取自PEP 526 - 变量注释的语法Python将继续保持动态类型的语言,作者们从未想过让类型提示成为必须的,即使是按照惯例 - fedorqui
1
这个回答解决了你的问题吗?Python 3.5 中的类型提示是什么? - AMC
2个回答

89

变量注释是什么?

变量注释只不过是从PEP 484定义的# type注释中迈出的下一步;这个改变的理由在 PEP 526相应章节中强调。

因此,与其用这种方式暗示类型:

primes = []  # type: List[int]

新增语法允许直接使用以下形式的赋值来对类型进行注释:New syntax was introduced
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 -- 函数注解 之后,函数就有了这个属性),其中附加了类型元数据:
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]}, {})

当使用ChainMap来获取给定类的注释(位于第一个映射中)以及其mro中定义的所有基类的注释(后续映射,{}表示对象)。

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

我是否被强制使用它?

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


3
随着PEP 585的引入,Python 3.9+中的一些事情发生了变化。这将使您的示例更改为primes: list[int] = []或者更简单的primes = list[int]() - Jeyekomon

58
:=之间的所有内容都是类型提示,所以primes确实被定义为List[int]并最初设置为空列表(stats最初为空字典,被定义为Dict[str, int])。 List[int]Dict[str, int]并不是下一个语法的一部分,而是已经在Python 3.5类型提示PEP中定义好了。Python 3.6 PEP 526 - 变量注释语法提案仅定义了将相同的提示附加到变量的语法;在此之前,您只能使用注释将类型提示附加到变量(例如primes = [] # List[int])。 ListDict都是泛型类型,表示您具有具体内容的列表或字典映射。
对于List,只有一个'argument'([...]语法中的元素),即列表中每个元素的类型。对于Dict,第一个参数是键类型,第二个参数是值类型。因此,primes列表中的所有值都是整数,并且stats字典中的所有键值对都是(str, int)对,将字符串映射到整数。请参阅 typing.Listtyping.Dict 的定义,以及关于 泛型部分,还有PEP 483 - 类型提示的理论
像函数中的类型提示一样,它们的使用是可选的,并且也被认为是 注释(只要有对象可以附加到这些对象上,因此在模块中的全局变量和类的属性上,而不是在函数中的局部变量上),您可以通过__annotations__ 属性来内省它们。您可以将任意信息附加到这些注释中,您并不严格限于类型提示信息。
您可能需要阅读完整的提案;它包含了一些新语法之外的额外功能;例如它指定了何时评估这些注释、如何内省它们以及如何声明某些内容为类属性而非实例属性等。

2
我能把类型提示视为一种“机器可读”的注释吗?因为它们不会影响代码的运行(除了obj.__annotations__属性)。 - iBug
4
@iBug: "annotations"是可被机器读取的注释,就像人类可以阅读的注释一样。 :-) - Martijn Pieters

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接