如何引用嵌套的 Python 数据类?

How to refer to nested Python dataclasses?

关于类似问答的注释:


我正在尝试将多个 Python @dataclass 装饰的 class 嵌套在另一个 class 中,稍后再 classes回头再看前面的。如果我根本不嵌套它们,它们会按预期工作,能够将第一个 class 定义到第二个 class:

的对象中
from dataclasses import dataclass, field

@dataclass
class A:
  z:int = field(default=0)

@dataclass
class B:
  a:A = field(default=A(z=1)) ### Object that is class A is included in class B

b = B(a=A(z=3))
print(f'b = B(a=A(z=3)); b.a.z={b.a.z}; b={b}')

但是如果我尝试在另一个 class(在本例中,不是数据class)中做同样的事情,“B”class 看不到“A” " class。在下面的代码中,将 a 定义为 A 的类型失败并出现 NameError:“name A is not defined”。我试过 A 和 C.A,都没有用。

请注意,C class 中的其他函数能够同时看到 A 和 B 就好了,只是在 dataclass B 中看不到 dataclass A.

class C:
  @dataclass
  class A:
    z:int = field(default=0)

  @dataclass
  class B:
    a:A = field(default=A(z=1)) ### NameError: name 'A' is not defined

  def __init__(self):
    self.b = C.B(a=C.A(z=3))

  def print_info(self):
    print(f'b = C.B(a=C.A(z=3)); b.a.z={self.b.a.z}; b={b}')

c = C()
c.print_info()

但是,如果我将它们转换为正常的 Python classes,它在嵌套情况下有效:

重新检查,结果发现这在正常 classes 中也有问题(根据下面的评论)。

奇怪的是,如果将 dataclass A 嵌套在 dataclass B 中,而 B 仍在 class C 中,它确实有效- B 可以直接访问 A,但 class C 中的任何其他内容都不能直接访问 A。

问题

是否可以定义嵌套数据classes,让后面的数据在同一级别访问前面的数据?如果可以,怎么做?

据我所知,这是由于 class definitions 的语义所致——强调我的:

The class’s suite is then executed in a new execution frame, using a newly created local namespace and the original global namespace. (Usually, the suite contains mostly function definitions.) When the class’s suite finishes execution, its execution frame is discarded but its local namespace is saved.

也就是说,任何 class 定义都只有模块全局命名空间(在这种情况下还不包含 C,因为它的套件还没有完成执行)和一个新的空的本地命名空间。

编辑

基于以上,这个可以一起被黑去工作,但我真的不会这样做...

from dataclasses import dataclass, field


class C:
    @dataclass
    class A:
        z: int = field(default=0)

    globals()["A"] = A  # "and the original global namespace..."

    @dataclass
    class B:
        a: A = field(default=A(z=1))

    def __init__(self):
        self.b = C.B(a=C.A(z=3))

    def print_info(self):
        print(f"{self.b.a.z=}")


c = C()
c.print_info()