Лучший способ перебрать более 1000 ключей и значений класса данных? - PullRequest
0 голосов
/ 17 марта 2020

У меня есть два класса данных, Маршрут и Факторы. Маршрут содержит значение и три копии Факторов. Маршрут не знает, сколько переменных факторов содержит. Я хочу получить имя этих переменных, а затем получить соответствующее значение каждой из них для каждой копии Факторов.

Вот то, что у меня сейчас есть:

@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

Может быть, я мог бы найти Route для каждой переменной, которая содержит тип данных Factors, и перебрать ее?

1 Ответ

1 голос
/ 17 марта 2020

Я бы оставил встроенные __str__ в покое и просто вызвал бы функцию visualize или что-то в классе Route, но это на вкус. Вы также не должны перегружать __init__ класса данных, если только вам это не нужно, просто разделите ваш входной диктет в конструкторе по умолчанию. __dict__, классы данных популярны благодаря использованию __slots__ для хранения их атрибутов, что может нарушить ваш код нетривиальным способом.

Так что я бы go что-то вроде этого:

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, *[f for f in 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 .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...