Есть крайне глубокий yaml-файл, до 20 уровней. Маленький кусочек для примера:
key-vars-test.yaml
default:
ui-key:
ferg: Привет
gtrh: Пока
wiki:
blocks_common: Пример
blocks_common_desktop:
blocks_b-access-button:
external_access: не только
lock: Закрытый
owner: владелец
restricted: Ограниченный
blocks_b-action: Пример 2
blocks_b-action-copy:
cant_copy_cluster: Не удалось скопировать раздел
data:
aside-header:
popover:
button_watch: Смотреть
description: Основы работы с интерфейсом, рекомендации и не только!
description-ext: Создайте свой первый алгоритм за 2 минуты
close-confirm: >-
У вас есть непримененные изменения. Вы уверены, что хотите закрыть
диалог?
chartkit:
button-spin-input:
error: Ошибка
categories: Категории
categories_test:
label_ya-podcasts-conn-description: >-
Это подключение позволит вам просматривать детальную статистику
прослушивания ваших подкастов.
По кнопке ниже вы получите ключ (OAuth-токен) — инструмент, который
позволит системе DataLens отобразить информацию по вашим подкастам.
Вы сможете самостоятельно выдавать доступы к статистике другим
людям, как описано в [документации]({{docLink}}). Доступ можно в
любой момент закрыть, отозвав выписанный токен.
label_ya-podcasts-conn: 123ddd
Мне надо получить конечные значения со всеми предыдущими ключами в определенном виде. Пример ожидаемого результата для приведенного выше кусочка:
key-vars.yaml
default: {{ ui-key.ferg }} : Привет
default: {{ ui-key.gtrh }} : Пока
default: {{ ui-key.wiki.blocks_common }} : Пример
default: {{ ui-key.wiki.blocks_common_desktop.blocks_b-access-button.external_access }} : не только
default: {{ ui-key.data.aside-header.popover.button_watch }} : Смотреть
default: {{ ui-key.data.aside-header.popover.description }} : Основы работы с интерфейсом, рекомендации и не только!
default: {{ ui-key.data.chartkit.button-spin-input.error }} : Ошибка
default: {{ ui-key.data.chartkit.categories }} : Категории
default: {{ ui-key.data.chartkit.categories_test.label_ya-podcasts-conn-description }} : 134
default: {{ ui-key.data.chartkit.categories_test.label_ya-podcasts-conn }} : 123ddd
Я использовал библиотеку
pyyaml, сделал из yaml-файла словарь, а потом прошелся по каждому элементу и добавлял каждый элементы в список, пока он не перестал быть словарем. В конце преобразовал список в файл. Но так как уровней около 20, получилась безумная лестница. Код, который у меня получился и работает:
for-habr.py
import yaml
contents = []
with open("key-vars-test.yaml", "r", encoding='utf-8') as file:
test = yaml.load(file, Loader=yaml.FullLoader)
#print(test){{{{
for key1, value1 in test.items():
for key2, value2 in value1.items():
for key3, value3 in value2.items():
if type (value3) is dict:
for key4, value4 in value3.items():
if type (value4) is dict:
for key5, value5 in value4.items():
if type (value5) is dict:
for key6, value6 in value5.items():
if type (value6) is dict:
for key7, value7 in value6.items():
if type (value7) is dict:
for key8, value8 in value7.items():
contents.append(f"{key1}: {{{{ {key2}.{key3}.{key4}.{key5}.{key6}.{key7}.{key8} }}}} : {value8}")
else:
contents.append(f"{key1}: {{{{ {key2}.{key3}.{key4}.{key5}.{key6}.{key7} }}}} : {value7}")
#print(f"{key1}: {{{{ {key2}.{key3}.{key4}.{key5}.{key6}.{key7} }}}} : {value7}")
else:
contents.append(f"{key1}: {{{{ {key2}.{key3}.{key4}.{key5}.{key6} }}}} : {value6}")
#print(f"{key1}: {{{{ {key2}.{key3}.{key4}.{key5}.{key6} }}}} : {value6}")
else:
contents.append(f"{key1}: {{{{ {key2}.{key3}.{key4}.{key5} }}}} : {value5}")
#print(f"{key1}: {{{{ {key2}.{key3}.{key4}.{key5} }}}} : {value5}")
else:
contents.append(f"{key1}: {{{{ {key2}.{key3}.{key4} }}}} : {value4}")
else:
contents.append(f"{key1}: {{{{ {key2}.{key3} }}}} : {value3}")
with open("key-vars.yaml", "w", encoding='utf-8') as file:
file.writelines("%s\n" % i for i in contents)
Прошу помочь оптимизировать код, избавившись от такой безумной вложенности. Наверняка можно ограничиться пару циклами, обновляя словарь, над которым проводятся манипуляции, но я никак не могу придумать как.
UPD: Так как запрос готового кода это нарушение п.5.12
Регламента, то общий ответ "обход вложенного словаря" получен, спасибо.
UPD2: По итогу больше помог ответ "распаковка словаря", чем "обход вложенного словаря".
Нашел библиотеку
flatten-dict, которая полностью решает проблему преобразования вложенных словарей в один плоский.
Итоговый рабочий код, который настроен под мой определенный вид:
for-habr-finally.py
import yaml
from flatten_dict import flatten
from flatten_dict.reducers import make_reducer
key_vars = []
with open("key-vars-test.yaml", "r", encoding='utf-8') as file:
key_vars_dict = yaml.load(file, Loader=yaml.FullLoader)
key_vars_flat_dict = flatten(key_vars_dict, reducer=make_reducer(delimiter='.'))
for key, value in key_vars_flat_dict.items():
key_vars.append(f"{{{{ {key[8:]} }}}} : {value}")
with open("key-vars.yaml", "w", encoding='utf-8') as file:
file.writelines("%s\n" % i for i in key_vars)