【问题标题】:Python nested dataclasses ...is this valid?Python 嵌套的数据类……这有效吗?
【发布时间】:2021-01-10 03:29:30
【问题描述】:

背景

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

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

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))

问题

我想知道是否有一种方法可以以自包含的方式定义类,而不是用一堆低级别的类来污染我的顶层。 所以上面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)

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

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

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)

...正确打印出red10.0 pt2 的默认值

问题

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

(这意味着它现在工作并不幸运,但将来可能会崩溃?...或者它只是丑陋而不是你如何做事?...或者它只是坏?)

...它肯定比组合在一起的大量顶级“迷你”数据类更简洁,更容易理解和支持一百万倍。

...这也比尝试使用 marshmellow 或 jerry 将 json 模式绑定到类结构模型要容易得多。

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

【问题讨论】:

    标签: python-3.7 python-dataclasses python-class


    【解决方案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))
    

    这样,您可以以最有意义的方式重新排序类定义。像 mypy 这样的静态类型检查器也尊重这种前向引用的方式,它是 the initial pep on type annotation 的一部分,所以没什么特别的。嵌套类也解决了这个问题,但更难阅读,since flat is better than nested

    【讨论】:

    • 感谢阿恩提供的信息。我不得不承认我忘记了前向引用。我想我仍然处于哲学观点,你有一个具有两个属性的元素。例如,在 Typescript 中,这没问题——你只需在你的类中创建一个结构: stuff: {color: str; size: float} - 但在 Python 中你不能,所以你必须使用组合。但是,如果我有一个具有 5 个“级别”并且每个可能有 10 个元素的数据类,我不知道是否最好必须定义 50 个顶级数据类,这样我就可以在某个时候将它们全部组合成一个复杂的.
    猜你喜欢
    • 2018-07-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-05
    • 2021-11-06
    • 1970-01-01
    • 1970-01-01
    • 2011-05-27
    相关资源
    最近更新 更多