Ищете, вероятно, лучший способ получить вложенные данные с помощью 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 перебирает список. По каждому пункту:
- Возьмите второй элемент кортежа
- получить nestedStats.entries (это еще один изречение)
- Call превращает этот dict в список кортежей
- Превратите этот список в список слов с ключом и описанием
- объединить список диктовок в один диктант
- взять все результаты итерации
Я рекомендую попробовать это и удалить части спецификации, чтобы посмотреть, что произойдет...
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)