У меня есть определение класса:
Определение класса
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 и извлечь ключи - это сервисы, graph_dep
это зависимости, скрипт сопоставляет зависимости на основе этих значений
Как правило, если вам не нужна исходная структура 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)
Что делает этот код:
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, чтобы пользователь получил правильное сообщение об ошибке, если структура неверна.
Спасибо! Работает как шарм
Что такое части
foo:
и- "bar"
в YAML? Они не встречаются в коде Python, который вы показываете.