Я бы оставил встроенные __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 .