Python中的自引用类?

22 投票
9 回答
19151 浏览
提问于 2025-04-16 05:06

在Python中,你能否创建一个类,其中的成员本身是指向同一个类的其他成员的指针?比如在C语言中,你可能会有这样一个表示二叉树节点的类:

struct node {
    int data;
    struct node* left;
    struct node* right;
} 

那么在Python中,你该如何等效地创建这个呢?

9 个回答

16

我觉得这可能会对你有帮助。

from typing_extensions import Self


class Node:
    """Binary tree node."""

    def __init__(self, left: Self, right: Self):
        self.left = left
        self.right = right

typing_extensions 提供了一个 Self 类,可以用来引用类本身,我觉得这是自我引用最优雅的方式(PEP 673)。


正如其他人提到的,你也可以使用字符串字面量(就是直接写字符串)。但是当你有多个类型提示的时候,就会出现问题。

# python 3.10
var: str | int

然后你写一些像这样的代码:

class Node:
    def __init__(self, var: 'Node' | SomeClass):
        self.var = var

这会引发一个错误,提示类型错误:不支持的操作数类型('str' 和 'type')。

18

虽然其他回答提到这不是因为动态类型的问题,但实际上在Python3中,这在类型注解方面是个很真实的问题。而且这样写是行不通的(注意方法参数的类型注解):

class A:
    def do_something_with_other_instance_of_a(self, other: A):
        print(type(other).__name__)

instance = A()
other_instance = A()

instance.do_something_with_other_instance_of_a(other_instance)

结果是:

   def do_something_with_other_instance_of_a(self, other: A):
   NameError: name 'A' is not defined

关于这个问题的更多信息可以在这里找到: https://www.python.org/dev/peps/pep-0484/#the-problem-of-forward-declarations

你可以使用字符串字面量来避免前向引用

在这里输入图片描述

另一种方法是在这种情况下不使用Python3风格的类型注解,

如果你需要保持代码与早期版本的Python兼容,这也是唯一的方法。

为了在我的IDE(PyCharm)中获得自动补全,你可以使用这样的文档字符串:

使用Python文档字符串而不是类型提示来避免类的自引用

更新: 另外,除了使用文档字符串,你还可以在注释中使用"type: "注解。这也能确保mypy静态类型检查能够正常工作(mypy似乎不关心文档字符串):

在这里输入图片描述

5

Python是一种动态语言。这意味着你可以在几乎任何时候给对象添加属性,而且可以使用任何类型的值。所以,你提到的问题在Python中是不存在的。

撰写回答