类内的类型提示

2024-04-24 17:08:42 发布

您现在位置:Python中文网/ 问答频道 /正文

class Node:
    def append_child(self, node: Node):
       if node != None:
        self.first_child = node
    self.child_nodes += [node]

我该怎么做node: Node?因为当我运行它时,它会显示name 'Node' is not defined

我应该移除: Node并在函数内部进行实例检查吗? 但是我如何访问node的属性(我希望它是Node类的实例)?

顺便说一句,我不知道如何在Python中实现类型转换


Tags: 实例nameselfnonenodechildifis
3条回答

类型检查中的“self”引用通常使用字符串完成:

class Node:
    def append_child(self, node: 'Node'):
       if node != None:
        self.first_child = node
    self.child_nodes += [node]

PEP-0484的"Forward references"部分对此进行了说明。

请注意这不会进行任何类型检查或转换。这是python(通常)完全忽略的类型提示。但是,第三方工具(例如mypy)使用类型提示对代码进行静态分析,并且可以在运行前生成错误。

1提示是可内省的,因此如果您真的想的话,可以使用它们来使用decorators等构建某种运行时检查器,但python默认不会这样做。

如果您只想得到问题的答案,请阅读mgilson's answer

mgilson的答案很好地解释了如何绕过Python的这个限制。但我认为很重要的一点是要很好地理解为什么这不起作用,所以我要给出一个解释。

Python与其他语言有点不同。在Python中,没有所谓的“声明”,就Python而言,代码只是代码。导入模块时,Python会创建一个新的名称空间(全局变量可以存在的地方),然后自上而下执行模块的每一行。def foo(args): code只是一个复合语句,它将一堆源代码捆绑到一个函数中,并将该函数绑定到名称foo。类似地,class Bar(bases): code创建一个类,立即执行所有代码(在一个单独的名称空间中,该名称空间包含代码可能创建的任何类级变量,特别是使用def创建的方法),然后将该类绑定到名称Bar。它必须立即执行代码,因为所有方法都需要立即创建。因为代码在绑定名称之前执行,所以不能引用代码顶层的类。不过,在方法内部引用类是完全可以的,因为在调用该方法之前,该代码不会运行。

(您可能想知道为什么我们不能先绑定名称,然后执行代码。事实证明,由于Python实现类的方式,在创建类对象之前,您必须知道哪些方法预先存在。可以创建一个空类,然后使用属性赋值一次将所有方法绑定到它(实际上,您可以通过编写class Bar: pass,然后执行def method1():...; Bar.method1 = method1等手动操作),但这将导致更复杂的实现,并且概念化有点困难,所以Python不会这样做。)

代码汇总:

class C:
    C  # NameError: C doesn't exist yet.
    def method(self):
        return C  # This is fine.  By the time the method gets called, C will exist.
C  # This is fine; the class has been created by the time we hit this line.

Python3.7和Python4.0以后的版本

从Python 3.7开始,Python可以通过PEP 563实现类型注释的延迟求值。在PEP 563中,注释作为字符串存储在__annotations__中。从Python 3.7开始,您可以通过^{}指令启用它:

from __future__ import annotations

这样就可以写:

class C:
    a: C
    def foo(self, b: C):
        ...

从Python4.0开始,这种行为将是正常的行为。

相关问题 更多 >