В ваших комментариях вы указываете, что предпочитаете загружать только один экземпляр Struct
. Однако, если вы хотите получить доступ к значению "value aaa"
, написав my_job.first_lvl.second_lvl.item_a.0.value_a
, вы не сможете сделать это, предоставив метод __getattr__
, так как это приведет к ошибке, сообщающей, что объект dict
не имеетатрибут second_lvl
(он имеет только ключ second_lvl
). __getattr__
никогда не вызывается, потому что в экземпляре Struct
поиск атрибутов не завершается.
Что вы можете сделать, это предоставить некоторый метод lookup
, который в качестве аргумента принимает "пунктирную" строку:
import ruamel.yaml
yaml_str = """\
first_lvl:
second_lvl:
item_a:
- value_a : "value aaa"
- value_b : "value bbb"
"""
class Struct:
def __init__(self, **entries):
self.__dict__.update(entries)
def lookup(self, s):
def recurse(d, names):
name = names[0]
if isinstance(d, list): # list indices cannot be strings
name = int(name)
if len(names) > 1:
return recurse(d[name], names[1:])
return d[name]
names = s.split('.')
return recurse(getattr(self, names[0]), names[1:])
yaml = ruamel.yaml.YAML(typ='safe')
my_job = Struct(**yaml.load(yaml_str))
print(my_job.lookup("first_lvl.second_lvl.item_a.0.value_a"))
, что дает:
value aaa
Этот ответ показывает альтернативное расширение структуры данных по умолчанию при использовании ruamel.yaml в режиме туда-обратно.
Если вы действительно хотите написать my_job.first_lvl.second_lvl.item_a.0.value_a
без кавычек, я не думаю, что есть способ обойти каждый уровень осознанием поиска атрибутов. Это означает расширение Struct
, так что класс может быть построен из сопоставления последовательностей и . Это можно сделать после загрузки YAML, но лучше всего выполнить IMO во время создания YAML.