Как я могу создать вложенные словарные ключи и назначить им значения из списка пар значений ключей пространства имен? - PullRequest
2 голосов
/ 20 апреля 2020

У меня есть переменные env, которые выглядят так:

CONFIG-SOMEKEY-SOMEOTHERKEY = val345
CONFIG-SOMEKEY-SOMEOTHEROTHERKEY = val678
CONFIG-ANOTHERKEY = val222

Я хочу создать из них словарь, который будет выглядеть так:

{
  'SOMEKEY': {
    'SOMEOTHERKEY': 'val3242',
    'SOMEOTHEROTHERKEY': 'val678'
  }
  'ANOTHERKEY': 'val222'
}

"CONFIG-" это префикс для обозначения того, с какими переменными это должно быть сделано, поэтому я могу легко отфильтровать их следующим образом:

config_fields = [i for i in os.environ if i.startswith("CONFIG-")]

Но я не уверен, как l oop над строкой, разделить на "-" и создать диктовку.

Во время цикла я думал, что смогу проверить, является ли он последним элементом, и присвоить значение, но как он узнает полный путь к ключам, на которых он включен?

Я подозреваю, что это это работа для рекурсии Я только сейчас точно знаю, как ее реализовать

Ответы [ 3 ]

2 голосов
/ 20 апреля 2020

Вы можете сделать:

data = ['CONFIG-SOMEKEY-SOMEOTHERKEY = val345',
        'CONFIG-SOMEKEY-SOMEOTHEROTHERKEY = val678',
        'CONFIG-ANOTHERKEY = val222']

result = {}
for e in data:
    key, value = e.split(" = ")  # split into key and value
    path = key.split("-")  # split the key into parts
    ref = result
    for part in path[1:-1]:
        ref[part] = part in ref and ref[part] or {}
        ref = ref[part]
    ref[path[-1]] = value  # take the last part of key and set the value

print(result)

Вывод

{'SOMEKEY': {'SOMEOTHERKEY': 'val345', 'SOMEOTHEROTHERKEY': 'val678'}, 'ANOTHERKEY': 'val222'}

Эта часть:

ref = result
for part in path[1:-1]:
    ref[part] = part in ref and ref[part] or {}
    ref = ref[part]
ref[path[-1]] = value

создаст вложенные словари, эквивалентно:

for part in path[1:-1]:
    if part not in ref:
        ref[part] = {}
    ref = ref[part]

Так что, если part находится в словаре, вы устанавливаете ref как значение, соответствующее part, в противном случае вы создаете новый словарь.

2 голосов
/ 20 апреля 2020

Вы можете использовать функцию assoc_in из toolz . Разделите имя на - и удалите префикс.

import os

from toolz.dictoolz import assoc_in

CONFIG={}

for k, v in os.environ.items():
    if k.startswith("CONFIG-"):
        assoc_in(CONFIG, k.split('-')[1:], v)

Если вы не хотите добавлять зависимость, вы можете увидеть реализацию assoc_in здесь . Более простой заменой может быть что-то вроде

def assoc_in(d, ks, v):
    for k in ks[:-1]:
        d = d.setdefault(k, {})
    d[ks[-1]] = v

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

1 голос
/ 20 апреля 2020

Вы можете получить переменные среды следующим образом:

import os

text = [f"{k} = {v}" for k,v in os.environ.items() if k.startswith("CONFIG-")]
print(env)

(вдохновлено Как получить доступ к значениям переменных среды? - особенно это ответ )

Тогда вы можете использовать дикты для итеративного разделения ваших значений:

text = """CONFIG-SOMEKEY-SOMEOTHERKEY = val345
CONFIG-SOMEKEY-SOMEOTHEROTHERKEY = val678
CONFIG-ANOTHERKEY = val222"""

text = text.split("\n")

d = {}

curr_d = d
for part in text:
    while "-" in part:
        a, b = part.split("-",1)
        if '-' in b:
            curr_d [a] = curr_d.get(a,{})
            curr_d = curr_d[a]
        part = b
    a, b = part.split("=",1)
    curr_d[a] = b

    curr_d = d

print(d)

Вывод:

{'CONFIG': {'SOMEOTHERKEY ': ' val345', 
            'SOMEOTHEROTHERKEY ': ' val678'}, 
 'ANOTHERKEY ': ' val222'}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...