使用类作为其方法中的参数的类型提示

时间:2016-10-14 17:39:06

标签: python python-3.x oop type-hinting

我在下面包含的代码会引发以下错误:

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

3 个答案:

答案 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