Создание объектов пользовательского класса из YAML в Python

У меня есть определение класса:

Определение класса

class Task(object):
    def __init__(self, name, *depends):
        self.__name    = name
        self.__depends = set(depends)

    @property
    def name(self):
        return self.__name

    @property
    def depends(self):
        return self.__depends

Остальная часть кода использует примерное определение, подобное этому:

a = Task("a", "b")
b = Task("b")

nodes = (a, b)

Я пытаюсь создать эти объекты динамически, анализируя YAML в отдельной функции, которая возвращает словарь data, а затем я создаю все объекты:

Yaml-файл

a:
  foo:
   - "bar"
  graph_dep:
  - "b"
b:
  foo:
   - "bar"

Я считаю, что смог добиться создания объектов a и b класса Task с помощью функции

def format_input(data):
    services = data.keys()
    holder = {Task(name=name) for name in services}
    return holder

q1: Как мне объединить их, чтобы получить объект nodes и получить тот же результат, что и при использовании примеров определений? q2: Как получить значения из graph_dep и добавить их в строку holder = {Task(name=name) for name in services}?

Извините, вопрос новичка в Python :)

Что такое части foo: и - "bar" в YAML? Они не встречаются в коде Python, который вы показываете.

flyx 10.12.2020 20:16

foo и bar не используются... Все, что мне нужно, это разобрать yaml и извлечь ключи - это сервисы, graph_dep это зависимости, скрипт сопоставляет зависимости на основе этих значений

Anton Teterine 10.12.2020 20:27
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
2
1 879
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Как правило, если вам не нужна исходная структура YAML, нет необходимости загружать ее в собственные типы Python. Вместо этого вы должны загружать их только в граф узлов YAML, а затем загружать из него нативную структуру, которую вы хотите получить:

import yaml

input = """
a:
  foo:
   - "bar"
  graph_dep:
  - "b"
b:
  foo:
   - "bar"
"""

class Task(object):
  def __init__(self, name, *depends):
    self.__name    = name
    self.__depends = set(depends)

  @property
  def name(self):
    return self.__name

  @property
  def depends(self):
    return self.__depends

  def __str__(self):
    return "Task({}, {})".format(self.__name, self.__depends)

def load_dependency_list(loader, node):
  for item in node.value:
    if item[0].value == "graph_dep":
      return loader.construct_sequence(item[1])
  return []

def load_tasks(loader, node):
  ret = ()
  for item in node.value:
    name = loader.construct_scalar(item[0])
    deplist = load_dependency_list(loader, item[1])
    ret += (Task(name, *deplist),)
  return ret

loader = yaml.SafeLoader(input)
nodes = load_tasks(loader, loader.get_single_node())
for node in nodes:
  print(node)

Что делает этот код:

  • получение графа узлов отдельного документа в файле YAML через get_single_node()
  • на возвращенном корневом узле выполните код загрузки

load_tasks и load_dependency_list обрабатывают уровни в YAML. PyYAML предоставляет средства для регистрации этих функций в качестве конструкторов, однако это имеет смысл только в том случае, если у вас есть теги во входных данных YAML (например, --- !nodes в качестве первой строки). Без тегов PyYAML не может автоматически отображать конструкторы, поэтому вам нужно реализовать процесс построения самостоятельно.

В этом случае load_dependency_list создает список, содержащийся в graph_dep, или возвращает пустой список, игнорируя другие вещи в узле YAML. load_tasks перебирает элементы верхнего уровня, создавая Task объект из каждого из них, и объединяет их в кортеж.

Я добавил метод __str__ к Task для вывода. Выход

Task(a, {'b'})
Task(b, set())

Этот код не имеет никаких гарантий, и я советую проверять правильные типы узлов всякий раз, когда вы обращаетесь к узлу YAML, чтобы пользователь получил правильное сообщение об ошибке, если структура неверна.

Спасибо! Работает как шарм

Anton Teterine 10.12.2020 21:57

Другие вопросы по теме