11

我有两个数据类,Route 和 Factors。Route 包含一个值和三个 Factors 副本。Route 不知道 factor 包含多少变量。我想获取这些变量的名称,然后为每个因子副本获取每个变量的值。

这是我目前拥有的:

@dataclass
class Factors:
    do: bool  # does it do the route
    hub: int # how many of the locations are hubs

    def __init__(self, do_init):
        self.do = do_init
        self.hub = 0 # will add later 

    def __str__(self):
        return "%s" % self.do


@dataclass
class Route:
    route: tuple
    skyteam: Factors
    star: Factors
    oneworld: Factors

    def __init__(self, route):
        self.route = route.get('route')
        # this could probably be done with one line loop and a variable with names
        self.skyteam = Factors(route.get('skyteam'))
        self.star = Factors(route.get('star'))
        self.oneworld = Factors(route.get('oneworld'))

    def __str__(self):
        table = [[self.route, "SkyTeam", "StarAlliance", "OneWorld"]] # var name is fine
        for var in Factors.__dict__.get('__annotations__').keys():  # for each factor
            factor = [var]
            factor.append(self.skyteam.__dict__.get(var))
            factor.append(self.star.__dict__.get(var))
            factor.append(self.oneworld.__dict__.get(var))
            table.append(factor)
        return tabulate.tabulate(table, tablefmt='plain')

输入是

{'route': ('BOS', 'DXB'), 'skyteam': True, 'star': True, 'oneworld': True}

电流输出为

('BOS', 'DXB')  SkyTeam  StarAlliance  OneWorld
do              True     True          True
hub             0        0             0

也许我可以搜索包含 Factors 数据类型的每个变量的 Route 并遍历这些变量?

4

4 回答 4

9

我还将使用__dataclass_fields__返回变量名称及其类型的字典。例如:

for field in mydataclass.__dataclass_fields__:
    value = getattr(mydataclass, field)
    print(field, value)
于 2021-06-01T02:19:28.167 回答
9

您可以使用dataclass.fields

from dataclasses import dataclass, fields

for field in fields(YourDataclass):
    print(field.name, getattr(YourDataclass, field.name))
于 2021-11-30T10:52:23.660 回答
3

我会不理会内置__str__函数,只在类上调用函数visualize或其他东西Route,但这就是品味。除非绝对必须,否则您也不应该重载__init__数据类,只需将输入 dict 放入默认构造函数中即可。

最后一点,尝试使用getattr/setattr过度访问__dict__,数据类很流行用于__slots__存储它们的属性,这会以一种不平凡的方式破坏你的代码。

所以我会用这样的东西,使用制表库来处理渲染:

from dataclasses import dataclass, fields
import tabulate

@dataclass
class Factor:
    do: bool
    hub: int = 0 # this is how to add a default value


@dataclass
class Route:
    route: tuple
    skyteam: Factor
    star: Factor
    oneworld: Factor

    def __post_init__(self):
        # turn Factor parameter dicts into Factor objects
        for field in fields(self):
            if issubclass(field.type, Factor):
                setattr(self, field.name, field.type(getattr(self, field.name)))

    def visualize(self):
        factors = {
            field.name: getattr(self, field.name)
            for field in fields(self)
            if issubclass(field.type, Factor)
        }
        rows = [[self.route, *factors]]  # header
        for field in fields(Factor):
            rows.append([field.name, *[getattr(f, field.name) for f in factors.values()]])
        print(tabulate.tabulate(rows))

这对你的例子很好:

>>> r = Route(**{'route': ('BOS', 'DXB'), 'skyteam': True, 'star': True, 'oneworld': True})
>>> r.visualize()
--------------  -------  ----  --------
('BOS', 'DXB')  skyteam  star  oneworld
do              True     True  True
hub             0        0     0
--------------  -------  ----  --------

如果您将更多字段添加到 Factor 类并将更多因子实例添加到 Route,则此解决方案应该继续工作。

于 2020-03-17T09:57:06.317 回答
1

要访问类本身中的字段,这是我尝试过的。

from dataclass import dataclass, fields

@dataclass
class someDataclass:
    def access_fields(self):
        for field in fields(self.__class__):
            print(field) # you get the Field() instances
于 2022-01-13T10:58:24.773 回答