59

我目前正在创建一个 python 线性代数模块,以供娱乐和练习该语言。我最近尝试向模块添加类型注释,如下所示:

class Vector:
     # Various irrelevant implementation details
     def __add__(self, other: Vector) -> Vector:
        # More implementation details....

但是,当我尝试导入它时,它会吐出一个NameError: Name 'Vector' is not defined. 我承认这个问题已经以某种形式在这里得到了回答,但它似乎并没有完全为我的情况提供答案。

我想知道的:

  • 我已经在这个文件中定义了这个类。为什么它说名称未定义?
  • 如何Vector以可用于注释的方式定义(作为 a type)?
4

2 回答 2

80

你有一个前向声明;函数(作为方法绑定)是在类之前创建的,所以这个名字Vector还不存在。只有当所有的类主体都执行完毕后,Python 才能创建class对象并将名称绑定Vector到它。

只需使用带有名称的字符串:

class Vector:
     # Various irrelevant implementation details
     def __add__(self, other: 'Vector') -> 'Vector':
        # More implementation details....

这不会影响您的 IDE 如何查看声明;加载整个模块后查找字符串,并在当前上下文中将其解析为有效的 Python 表达式。由于类Vector在整个模块加载后就存在,因此'Vector'可以正确地将字符串转换为类对象。

另请参阅前向引用规范

当类型提示包含尚未定义的名称时,该定义可以表示为字符串文字,稍后再解析。

[...]

字符串文字应该包含一个有效的 Python 表达式 [...],并且一旦模块完全加载,它应该不会出错。

from __future__ import annotations从 Python 3.7 开始,您可以通过在模块顶部添加指令来使给定模块中的所有注解表现得像前向注解(不将它们包含在字符串文字中) 。在 Python 3.10 及更高版本中,这已成为默认行为。请参阅PEP 563 -注释的延迟评估。请注意,在注释之外,您可能仍需要使用前向引用语法(字符串文字),例如在类型别名中(就 Python 而言,这是一个常规变量赋值)。

于 2016-03-29T14:15:41.107 回答
46

如果您使用的是Python 3.7及更高版本。看一下注释的延迟评估

从 Python 3.7 开始,它将被允许,只需添加:

from __future__ import annotations

还要注意

它将成为 Python 3.10 中的默认设置。

于 2018-02-25T13:10:05.470 回答