Изменение элемента вложенного словаря по ссылке, созданной из списка - PullRequest
1 голос
/ 10 июля 2020
  1. Код:

    def main():
     nested_dict = {'A': {'A_1': 'value_1', 'B_1': 'value_2'},
                    'B': 'value_3'}
    
     access_pattern = ['A', 'B_1']
     new_value = 'value_4'
    
     nested_dict[access_pattern] = new_value
    
     return nested_dict
    
Справочная информация:

Как видно, у меня есть переменная с именем nested_dict - на самом деле она содержит сотни элементов с разными количество подэлементов в каждом (я упрощаю его для примера).

Мне нужно изменить значение некоторых элементов внутри этого словаря, но какие именно элементы не определены заранее. Указанный c «путь» к элементам, которые необходимо изменить, будет предоставлен переменной access_pattern , которая каждый раз будет разной.

Проблема:

Я знаю, как ссылаться на значение словаря с помощью этой функции functools.reduce(dict.get, access_pattern, nested_dict). Однако я не знаю, как универсально изменить (независимо от типа содержащейся переменной) значение access_pattern в словаре .

Предоставленный код создает TypeError, который я не знаю, как элегантно преодолеть. Я придумал какое-то решение, указанное в 4.

Возможные решения:

 if len(access_pattern) == 1:
   nested_dict[access_pattern[0]] = new_value
 elif len(access_pattern) == 2:
   nested_dict[access_pattern[0]][access_pattern[1]] = new_value
 ...
 So on for all len()

Это просто кажется ОЧЕНЬ неэлегантным и болезненным. Есть ли более практичный способ добиться этого?

Ответы [ 2 ]

0 голосов
/ 12 июля 2020

Вы можете использовать рекурсию

def set_value(container, key, value):
    if len(key) == 1:
        container[key[0]] = value
    else:
        set_value(container[key[0]], key[1:], value)

, но явное l oop, вероятно, будет более эффективным

def set_value(container, key, value):
    for i in range(len(key)-1):
        container = container[key[i]]
    container[key[-1]] = value
0 голосов
/ 10 июля 2020

Использовать рекурсию

def edit_from_access_pattern(access_pattern, nested_dict, new_value):
    if len(access_pattern) == 1:
        nested_dict[access_pattern[0]] = new_value
    else:
        return edit_from_access_pattern(access_pattern[1:], nested_dict[access_pattern[0], new_value]
...