Home > other >  How to refer to nested Python dataclasses?
How to refer to nested Python dataclasses?

Time:10-25

Notes On Similar Q&As:


I'm trying to do a simple nesting of multiple Python @dataclass decorated classes within another class, and have later classes refer back to the earlier ones. If I do not nest them at all, they work as expected, being able to include the first class defined into an object in the second 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}')

But if I try to do the same inside of another class (in this case, not a dataclass), the "B" class cannot see the "A" class. In the below code, the definition of a as a type of A fails with a NameError: "name A is not defined". I've tried A and C.A, neither work.

Note that the other functions in the C class are able to see both A and B just fine, just inside dataclass B cannot see 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()

However, if I convert these to normal Python classes, it works in the nested case:

Rechecking, it turns out this is broken in normal classes as well (per comment below).

Strangely, if one nests dataclass A inside dataclass B, with B still inside class C, it does work - B has direct access to A, but nothing else in class C has direct access to A.

Question

Is it possible to define nested dataclasses with having the later ones access the earlier ones at the same level? If so, how?

CodePudding user response:

To my best understanding, this is due to the semantics for class definitions – emphasis mine:

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.

That is, any class definition only ever has the module-global namespace (which does not yet contain C in this case, since its suite hasn't finished executing) and a new empty local namespace.

  • Related