Ищете, вероятно, лучший способ получить вложенные данные с помощью glom?

У меня есть особенно неприятный объект статистики из системы, из которой мне нужно получить данные (две из многих записей статистики, показанных для краткости).

 'https://localhost/mgmt/tm/sys/performance/all-stats/TMM%20Memory%20Used': {'nestedStats': {'entries': {'Average': {'description': '5'},
                                                                                                         'Current': {'description': '5'},
                                                                                                         'Max(since 2019_11_12T02:47:10Z)': {'description': '5'},
                                                                                                         'Memory Used': {'description': 'TMM '
                                                                                                                                        'Memory '
                                                                                                                                        'Used'}}}},
 'https://localhost/mgmt/tm/sys/performance/all-stats/Utilization': {'nestedStats': {'entries': {'Average': {'description': '9'},
                                                                                                 'Current': {'description': '10'},
                                                                                                 'Max(since 2019_11_12T02:47:10Z)': {'description': '53'},
                                                                                                 'System CPU Usage': {'description': 'Utilization'}}}}}

В настоящее время я использую метод.get несколько раз во вложенных стеках, но в эти выходные я слушал автора модуля glom на Talk Python и подумал, что это может быть для меня гораздо более чистым решением. И это так, поскольку этот код делает так, чтобы у меня были все данные в цикле без сумасшедших слоев методов get (первый пример, изображенный выше, над которым я работаю сегодня вечером). Внешний ключ - это длинный URL, внутренний ключ - это avg/current/max/desc.

stats = b.tm.sys.performances.all_stats.load()
for k, v in stats.entries.items():
    print('\n')
    spec = f'entries.{k}.nestedStats.entries'
    v_stats = glom(stats, spec)
    for k, v, in v_stats.items():
        spec = f'{k}.description'
        stat_vals = glom(v_stats, spec)
        print(f'{k}: {stat_vals}')

Что приводит к нужным мне данным:

Average: 5
Current: 5
Max(since 2019_11_12T02:47:10Z): 5
Memory Used: TMM Memory Used

Тем не менее, сейчас у меня нет контроля над данными, я просто распечатываю их. Я не думаю, что я сейчас гробу силу glom, и мне было любопытно, может ли кто-нибудь указать мне пример, который поможет мне понять? Конечная цель - объединить все эти данные в единый список из 4 словарей.

1 ответ

Решение

Прежде чем попробовать это, убедитесь, что glom обновлен до текущей версии 19.11.0 или выше.

То, что вы просите, в документации glom называется назначением, управляемым данными, а не силой glom.

См. Документацию по glom здесь

Чтобы заставить его работать, вам могут понадобиться лямбды и / или обычный код Python.

Ниже представлена ​​моя рабочая попытка, скопируйте строки вашего примера в переменную d.

from glom import glom, Call, T, Iter

d = { ... }  # put your example lines into this dictionary.

def get_desc(subdict):
    return {k: v.get('description', None) 
            for k,v in subdict[1]['nestedStats']['entries'].items()}

spec = (Call(list, args=(T.items(),) ), Iter().map(get_desc).all())

result = glom(d, spec)

print(result)

приводит к

[
{'Average': '5', 'Current': '5', 'Max(since 2019_11_12T02:47:10Z)': '5', 'Memory Used': 'TMM Memory Used'}, 
{'Average': '9', 'Current': '10', 'Max(since 2019_11_12T02:47:10Z)': '53', 'System CPU Usage': 'Utilization'}
]

ОБНОВИТЬ

Версия ниже дает тот же результат, но не требует вспомогательной функции.

Что делает спецификация:

  • Call превращает внешний dict в список кортежей
  • Iter перебирает список. По каждому пункту:
    1. Возьмите второй элемент кортежа
    2. получить nestedStats.entries (это еще один изречение)
    3. Call превращает этот dict в список кортежей
    4. Превратите этот список в список слов с ключом и описанием
    5. объединить список диктовок в один диктант
  • взять все результаты итерации

Я рекомендую попробовать это и удалить части спецификации, чтобы посмотреть, что произойдет...

from glom import glom, Call, T, Iter, merge

# d = { ... }  # put your example lines into this dictionary.

spec = (
    Call(list, args=(T.items(),)),
    Iter(
        (
            T[1],
            "nestedStats.entries",
            Call(list, args=(T.items(),)),
            [{T[0]: (T[1], "description")}],
            merge,
        )
    ).all(),
)

result = glom(d, spec)

print(result)
Другие вопросы по тегам