Python 嵌套数据类...这有效吗?

Ric*_*ard 5 python-3.7 python-dataclasses python-class

背景

我使用数据类创建嵌套数据结构,用它来表示复杂的测试输出。

以前,我一直通过创建多个顶级数据类然后使用组合来创建层次结构:

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))
Run Code Online (Sandbox Code Playgroud)

问题

我想知道是否有一种方法以独立的方式定义类,而不是用一堆较低级别的类污染我的顶级。所以上面, dataclass 的定义Point包含 的定义Meta,而不是顶层的定义。

解决方案?

我想知道是否可以将内部(数据类)类与数据类一起使用并使一切正常工作。

所以我尝试了这个:

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)
Run Code Online (Sandbox Code Playgroud)

这一切似乎都有效 - 打印输出全部正常工作,并且对(子)成员元素的分配也有效。

您甚至可以支持嵌套元素的默认值:

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)
Run Code Online (Sandbox Code Playgroud)

...正确打印red10.0默认 pt2

问题

这是实现嵌套数据类的正确方法吗?

(意思是它现在能工作并不幸运,但将来可能会坏掉?……或者它只是丑陋而不是你做事的方式?……或者它只是糟糕?)

...它肯定比组合在一起的无数顶级“迷你”数据类要干净得多,并且更容易理解和支持一百万倍。

...这也比尝试使用 marshmellow 或偷工减料地将 json 模式转换为类结构模型要容易得多。

...它也很简单(我喜欢)

Arn*_*rne 1

您可以只使用字符串来注释尚不存在的类:

from dataclasses import dataclass

@dataclass
class Point:
    x: float
    y: float
    stuff: "Meta"

@dataclass
class Meta:
    color: str 
    size: float


point1 = Point(x=5, y=-5, stuff=Meta(color='blue', size=20))
Run Code Online (Sandbox Code Playgroud)

这样,您就可以以最有意义的方式重新排序类定义。像 mypy 这样的静态类型检查器也尊重这种前向引用的方式,这是类型注释的初始 pep的一部分,所以没有什么奇怪的。嵌套类也可以解决问题,但在我看来更难阅读,因为扁平比嵌套更好