You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何解决Python 3.12中定义树形结构时的循环引用问题

解决Python 3.12中玫瑰树类型的循环引用问题

我按照教程使用Python 3.12运行以下代码时出现错误:

from dataclasses import dataclass
from typing import Callable

type RoseTree[T] = Branch[T] | Leaf[T]

@dataclass
class Branch[A]:
    branches: list[RoseTree[A]]

    def map[B](self, f: Callable[[A], B]) -> Branch[B]:
        return Branch([b.map(f) for b in self.branches])


@dataclass
class Leaf[A]:
    value: A

    def map[B](self, f: Callable[[A], B]) -> Leaf[B]:
        return Leaf(f(self.value))

运行后报错:

Traceback (most recent call last):
  File "/mnt/c/Users/Pierre-Olivier/Documents/python/3.12/a.py", line 8, in <module>
    class Branch[A]:
  File "/mnt/c/Users/Pierre-Olivier/Documents/python/3.12/a.py", line 8, in <generic parameters of Branch>
    class Branch[A]:
  File "/mnt/c/Users/Pierre-Olivier/Documents/python/3.12/a.py", line 11, in Branch
    def map[B](self, f: Callable[[A], B]) -> Branch[B]:
  File "/mnt/c/Users/Pierre-Olivier/Documents/python/3.12/a.py", line 11, in <generic parameters of map>
    def map[B](self, f: Callable[[A], B]) -> Branch[B]:
                                             ^^^^^^
NameError: name 'Branch' is not defined

如果调换RoseTree与Branch、Leaf的定义顺序,依然报错:

Traceback (most recent call last):
  File "/mnt/c/Users/Pierre-Olivier/Documents/python/3.12/a.py", line 6, in <module>
    class Branch[A]:
  File "/mnt/c/Users/Pierre-Olivier/Documents/python/3.12/a.py", line 6, in <generic parameters of Branch>
    class Branch[A]:
  File "/mnt/c/Users/Pierre-Olivier/Documents/python/3.12/a.py", line 7, in Branch
    branches: list[RoseTree[A]]
                   ^^^^^^^^
NameError: name 'RoseTree' is not defined

这是典型的循环引用问题:RoseTree依赖未定义的Branch和Leaf,而Branch又依赖未定义的RoseTree,以下是两种可行的解决方法:

解决方法

方式1:使用字符串字面量做前向引用

通过将未定义的类型用字符串包裹,让类型检查器在后续分析中解析这些引用:

from dataclasses import dataclass
from typing import Callable

@dataclass
class Branch[A]:
    # 用字符串引用尚未定义的RoseTree
    branches: list["RoseTree[A]"]

    def map[B](self, f: Callable[[A], B]) -> "Branch[B]":
        return Branch([b.map(f) for b in self.branches])


@dataclass
class Leaf[A]:
    value: A

    def map[B](self, f: Callable[[A], B]) -> "Leaf[B]":
        return Leaf(f(self.value))

# 此时Branch和Leaf已定义,可以正常声明RoseTree
type RoseTree[T] = Branch[T] | Leaf[T]

方式2:使用Self类型简化方法返回注解(Python 3.11+)

Python 3.11引入的Self类型可以直接指代当前类的实例类型,避免显式引用未完全定义的类名:

from dataclasses import dataclass
from typing import Callable, Self

@dataclass
class Branch[A]:
    branches: list["RoseTree[A]"]

    def map[B](self, f: Callable[[A], B]) -> Self[B]:
        return Branch([b.map(f) for b in self.branches])


@dataclass
class Leaf[A]:
    value: A

    def map[B](self, f: Callable[[A], B]) -> Self[B]:
        return Leaf(f(self.value))

type RoseTree[T] = Branch[T] | Leaf[T]

原理说明

Python解析类定义时,类本身在类体内部尚未完成定义,直接引用类名会触发NameError。字符串字面量形式的类型注解会被类型检查器延迟解析,从而绕过循环引用的问题;Self类型则是专门用来指代当前类的实例类型,无需显式写出类名,自然避免了前向引用冲突。

内容的提问来源于stack exchange,提问作者Pierre-olivier Gendraud

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 01:50:16