Как применить функцию ко всем значениям словаря произвольной вложенности?

Есть больше 50 yml файлов. В каждом из которых в среднем 100 строк такого вида:

et:
  users:
    layout:
      closing_title: Закрытие договора аренды бокса
      dashboard: Главная
      my_profile: Мои данные
      my_units: Мои боксы
      payment_method: Способы оплаты
      hello: Здравствуйте, %{name}!
      unit: Бокс %{number}
      note_pending_verification: >-
        Доступ к боксу откроется после подтверждения личности
      unit_access_status: 'Статус:'
      unit_access_open: Доступен для посещения

Мне нужно взять каждое значение на русском и заменить.

Как можно это сделать?

Я пробовал сделать это с помощью словарей, вот так:

def main():
    with open("locales/activemodel.ru.yml", 'r', encoding='utf-8') as stream:
        try:
            a = yaml.safe_load(stream)
            for k, v in a["ru"].items():
                for l, m in v["attributes"].items():
                    slovo = m

        except yaml.YAMLError as exc:
            print(exc)

Но проблема в том, что файлов много, и у всех разная структура. Поэтому, сидеть и менять названия ключей в коде каждую секунду по времени будет так же, если бы я делал все вручную.

Какие могут быт решения, может есть какие то более удачные библиотеки, или делать это с помощью нахождения русский букв?


Ответы (1 шт):

Автор решения: MaxU

Воспользуйтесь этим решением:

from collections.abc import Mapping


def translate(text):
   # здесь делаете замену текста
   return "translated"


def map_nested_dicts(ob, func):
    if isinstance(ob, Mapping):
        return {k: map_nested_dicts(v, func) for k, v in ob.items()}
    else:
        return func(ob)

или этим решением:

def apply_recursive(func, obj):
    if isinstance(obj, dict):  # if dict, apply to each key
        return {k: apply_recursive(func, v) for k, v in obj.items()}
    elif isinstance(obj, list):  # if list, apply to each element
        return [apply_recursive(func, elem) for elem in obj]
    else:
        return func(obj)

Пример:

In [69]: apply_recursive(translate, d)
Out[69]:
{'et': {'users': {'layout': {'closing_title': 'translated',
    'dashboard': 'translated',
    'my_profile': 'translated',
    'my_units': 'translated',
    'payment_method': 'translated',
    'hello': 'translated',
    'unit': 'translated',
    'note_pending_verification': 'translated',
    'unit_access_status': 'translated',
    'unit_access_open': 'translated'}}}}
→ Ссылка