我在下面包含的代码会引发以下错误:
NameError: name 'Vector2' is not defined
在这一行:
def Translate (self, pos: Vector2):
为什么Python无法识别Vector2
方法中的Translate
类?
class Vector2:
def __init__(self, x: float, y: float):
self.x = x
self.y = y
def Translate(self, pos: Vector2):
self.x += pos.x
self.y += pos.y
答案 0 :(得分:14)
因为当它遇到Translate
时(编译类主体时),Vector2
尚未定义(它当前正在编译,名称绑定尚未执行); Python自然会抱怨。
由于这是一种常见的场景(在该类的主体中类型提示类),您应该使用 forward reference 将其括在引号中:
class Vector2:
# __init__ as defined
def Translate(self, pos: 'Vector2'):
self.x += pos.x
self.y += pos.y
Python(以及符合PEP 484
的任何检查员)都会理解您的提示并正确注册。通过typing.get_type_hints
访问__annotations__
时,Python确实会识别出来:
from typing import get_type_hints
get_type_hints(Vector2(1,2).Translate)
{'pos': __main__.Vector2}
从Python 3.7开始,这已经改变了;见abarnert's answer below。
答案 1 :(得分:2)
您要求的功能称为前向(类型)引用,并且已经从3.7(在PEP 563中)添加到Python中。 1 所以这现在有效:
from __future__ import annotations
class C:
def spam(self, other: C) -> C:
pass
注意__future__
statement。这是必要的until 4.0。
不幸的是,在Python 3.6及更早版本中,此功能不可用,因此您必须使用字符串注释,如Jim Fasarakis Hilliard's answer中所述。
Mypy已经支持前向声明,即使是在Python 3.6下运行 - 但是如果静态类型检查器说你的代码没问题但是当你试图实际上解释器引发NameError
时,它对你没有多大好处跑吧。
<子> 1。这已经作为PEP 484中的一个可能特征进行了讨论,但是在人们在注释中使用前向声明的经验之后推迟到以后。 PEP 563 / Python 3.7就是“以后”。
答案 2 :(得分:0)
也许另一种选择是使用空的实现先前定义该类。我猜最常见的解决方案是forward reference,但我的建议是类型安全的,毕竟这是添加类型的目的。
class Vector2:
pass
class Vector2:
def __init__(self, x: float, y: float):
self.x = x
self.y = y
def Translate(self, pos: Vector2):
self.x += pos.x
self.y += pos.y