Background
I'm using dataclasses to create a nested data structure, that I use to represent a complex test output.
Previously I'd been creating a hierarchy by creating multiple top-level dataclasses and then using composition:
from dataclasses import dataclass
@dataclass
class Meta:
color: str
size: float
@dataclass
class Point:
x: float
y: float
stuff: Meta
point1 = Point(x=5, y=-5, stuff=Meta(color='blue', size=20))
Problem
I was wondering if there was a way of defining the classses in a self-contained way, rather than polluting my top-level with a bunch of lower-level classes.
So above, the definition of Point
dataclass contains the definition of Meta
, rather than the definition being at the top level.
Solution?
I wondered if it's possible to use inner (dataclass) classes with a dataclass and have things all work.
So I tried this:
rom dataclasses import dataclass
from typing import get_type_hints
@dataclass
class Point:
@dataclass
class Meta:
color: str
size: float
@dataclass
class Misc:
elemA: bool
elemB: int
x: float
y: float
meta: Meta
misc: Misc
point1 = Point(x=1, y=2,
meta=Point.Meta(color='red', size=5.5),
misc=Point.Misc(elemA=True, elemB=-100))
print("This is the point:", point1)
print(point1.x)
print(point1.y)
print(point1.meta)
print(point1.misc)
print(point1.meta.color)
print(point1.misc.elemB)
point1.misc.elemB = 99
print(point1)
print(point1.misc.elemB)
This all seems to work - the print outputs all work correctly, and the assignment to a (sub) member element works as well.
You can even support defaults for nested elements:
from dataclasses import dataclass
@dataclass
class Point:
@dataclass
class Meta:
color: str = 'red'
size: float = 10.0
x: float
y: float
meta: Meta = Meta()
pt2 = Point(x=10, y=20)
print('pt2', pt2)
...prints out red
and 10.0
defaults for pt2 correctly
Question
Is this a correct way to implement nested dataclasses?
(meaning it's just not lucky it works now, but would likely break in future? ...or it's just fugly and Not How You Do Things? ...or it's just Bad?)
...It's certainly a lot cleaner and a million times easier to understand and upport than a gazillion top-level 'mini' dataclasses being composed together.
...It's also a lot easier than trying to use marshmellow or jerry-rigging a json schema to class structure model.
...It also is very simple (which I like)