21

在 Python 3.6 中,语言中引入了新的变量注释。

但是,当类型不存在时,可能会发生两种不同的情况:

>>> def test():
...     a: something = 0
... 
>>> test()
>>> 
>>> a: something = 0
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'something' is not defined

为什么不存在的类型处理行为不同?它不会导致人们忽略函数中未定义的类型吗?


笔记

尝试使用 Python 3.6 RC1 和 RC2 - 相同的行为。

PyCharmsomething在函数内部和外部都突出显示为“未解析的引用”。

4

4 回答 4

14

局部变量(即函数内部)的行为至少记录在Runtime Effects of Type Annotations部分:

注释局部变量将导致解释器将其视为局部变量,即使它从未被分配给。不会评估局部变量的注释:

def f():
    x: NonexistentName  # No error.

并继续解释全局变量的区别:

但是,如果它在模块或类级别,则将评估类型:

x: NonexistentName  # Error!
class X:
    var: NonexistentName  # Error!

这种行为让我感到惊讶,所以我只能提供我的猜测:如果我们将代码放在一个模块中,那么 Python 想要存储注释。

# typething.py
def test():
    a: something = 0

test()


something = ...

a: something = 0

然后导入它:

>>> import typething
>>> typething.__annotations__
{'a': Ellipsis}
>>> typething.test.__annotations__
{}

为什么有必要将它存储在模块对象上,而不是函数对象上 - 我还没有一个好的答案。也许是出于性能原因,因为注释是通过静态代码分析生成的,并且这些名称可能会动态更改:

...在本地提供注释的价值并不能抵消必须在每个函数调用上创建和填充注释字典的成本。因此,功能级别的注释不会被评估和存储。

于 2016-12-22T21:59:17.047 回答
7

最直接的答案(补充@wim 的答案)来自讨论提案的 Github 上的问题跟踪器:

[..] 最后,当地人。在这里,我认为我们不应该存储类型 -在本地提供可用注释的价值不足以抵消在每个函数调用上创建和填充字典的成本

事实上,我什至不认为应该在函数执行期间评估类型表达式。例如:

def side_effect():
    print("Hello world")
def foo():
    a: side_effect()
    a = 12
    return a
foo()

不应该打印任何东西。(类型检查器也会抱怨side_effect()不是有效类型。)

来自 BDFL 本人:-) 也没有创​​建字典,也没有执行评估。

目前,函数对象仅存储其定义中提供的注释:

def foo(a: int): 
    b: int = 0

get_type_hints(foo)   # from typing
{'a': <class 'int'>}

为局部变量注释创建另一个字典显然被认为成本太高。

于 2016-12-23T00:00:21.853 回答
4

您可以访问https://www.python.org/ftp/python/3.6.0/并下载 RC2 版本以测试注释,但 wim 所说的已发布版本尚未发布。但是,我确实使用 Python3.6 解释器下载并尝试了您的代码,但没有出现任何错误。

于 2016-12-22T21:39:09.320 回答
-1

你可以试试这样写:

>>>a: 'something' = 0
于 2016-12-30T20:30:52.317 回答