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

Van*_*tas 16 python oop type-hinting python-3.x

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

NameError: name 'Vector2' is not defined 
Run Code Online (Sandbox Code Playgroud)

在这一行:

def Translate (self, pos: Vector2):
Run Code Online (Sandbox Code Playgroud)

为什么Python不能Vector2Translate方法中识别我的类?

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
Run Code Online (Sandbox Code Playgroud)

Jim*_*ard 22

因为当它遇到Translate(编译类体时),Vector2尚未定义(它当前正在编译,尚未执行名称绑定); Python自然会抱怨.

由于这是一个常见的场景(在该类的主体中类型提示类),您应该通过将其括在引号中来使用它的前向引用:

class Vector2:    
    # __init__ as defined

    def Translate(self, pos: 'Vector2'):    
        self.x += pos.x
        self.y += pos.y
Run Code Online (Sandbox Code Playgroud)

Python(以及任何符合的检查员PEP 484)将理解您的提示并适当地注册它.__annotations__通过typing.get_type_hints以下方式访问时,Python确实识别出来:

from typing import get_type_hints

get_type_hints(Vector2(1,2).Translate)
{'pos': __main__.Vector2}
Run Code Online (Sandbox Code Playgroud)

从Python 3.7开始,这已经改变了; 请参阅下面的abarnert的回答.


aba*_*ert 8

您要求的功能称为正向(类型)引用,并且从3.7(在PEP 563中)起已添加到Python中。1因此,这现在有效:

from __future__ import annotations
class C:
    def spam(self, other: C) -> C:
        pass
Run Code Online (Sandbox Code Playgroud)

注意__future__声明直到4.0才需要。

不幸的是,在Python 3.6及更早版本中,此功能不可用,因此您必须使用字符串注释,如Jim Fasarakis Hilliard的答案所述

Mypy已经支持前向声明,即使在Python 3.6下运行时也是如此-但是如果静态类型检查器说您的代码很好,但是NameError当您尝试实际运行它时,解释器会引发一个正向声明,这对您没有多大帮助。


1.这已在PEP 484中讨论为可能的功能,但在人们对在批注中使用前向声明有更多经验之后,将其推迟到以后。PEP 563 / Python 3.7就是“后来的”。