Вложенные ключи dict как переменная

Должен быть более изящный способ сделать это, но я не могу понять, как создать единую функцию для чтения / записи значений на разные уровни dict, это «лучшее», что я мог придумать:

table = {
    'A': {
        'B': '2',
        'C': {
            'D':'3'
        }
    }
}
first = 'A'
second1 = 'B'
second2 = 'C'
third = 'D'

def oneLevelDict(first):
    x = table[first]
    print(x)

def twoLevelDict(first, second):
    x = table[first][second]
    print(x)

def threeLevelDict(first, second, third):
    x = table[first][second][third]
    print(x)

oneLevelDict(first)
twoLevelDict(first, second1)
threeLevelDict(first, second2, third)

Не точный обман, но в какой-то степени связанный: stackoverflow.com/questions/1373164/…

TrebledJ 10.01.2019 06:35

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

Grismar 10.01.2019 06:45
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
2
54
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

Вы можете использовать * args для передачи произвольного количества аргументов функции. Затем вы можете использовать цикл для обхода уровней.

get_any_level(*keys):
    d = table
    for key in keys:
        d = d[key]
    return d

Теперь у вас есть одна функция, которая может заменить три, которые у вас были раньше:

print(get_any_level(first))
print(get_any_level(first, second1))
print(get_any_level(first, second2, third))

Вы также можете использовать эту функцию для записи на произвольный уровень:

get_any_level(first)[second1] = 17

Лучше всего написать отдельную функцию:

def put_any_level(value, *keys):
    get_any_level(*keys[:-1])[keys[-1]] = value

put_any_level(17, first, second1)

value должен стоять первым в списке аргументов, если вы не хотите, чтобы он содержал только ключевые слова, потому что *keys будет использовать все позиционные аргументы. Это не обязательно плохая альтернатива:

def put_any_level(*keys, value):
    get_any_level(*keys[:-1])[keys[-1]] = value

Аргумент ключевого слова добавляет ясности:

put_any_level(first, second1, value=17)

Но это также приведет к ошибке, если вы попытаетесь передать его как позиционный аргумент, например put_any_level(first, second1, 17).

Пара второстепенных моментов:

  1. Принято использовать CamelCase только для имен классов. Переменные и функции обычно записываются в нижнем регистре.
  2. Функция обычно должна делать что-то одно, и делать это хорошо. В этом случае я отделил задачу поиска вложенного значения от задачи его отображения, дав функции возвращаемое значение.

Это лучший ответ, чем мой.

Aditya 10.01.2019 06:36

@ Адитья. Я ценю то, что ты это говоришь.

Mad Physicist 10.01.2019 06:39

@MadPhysicist - спасибо за объяснение. * args был ключом! Также оцените советы по соглашениям - новый язык - новые соглашения.

MattYYC 11.01.2019 00:57

@MattYYC рад, что вам понравилось. Вы можете выбрать ответ, нажав на галочку рядом с ним.

Mad Physicist 11.01.2019 01:03

Этого можно добиться с помощью * args. Подробнее об этом здесь

И вот как это сделать:

def allLevelDict(*argv):
  if len(argv) == 1:
    x  = table[argv[0]]
    print (x)
  elif len(argv) == 2:
    x  = table[argv[0]][argv[1]]
    print (x)
  elif len(argv) == 3:
    x  = table[argv[0]][argv[1]][argv[2]]
    print (x)
allLevelDict(first)
allLevelDict(first, second1)
allLevelDict(first, second2, third)

Под x = table[first] вы имели в виду x = table[argv[0]]?

Mad Physicist 10.01.2019 06:38

@MadPhysicist Сейчас изменил. Спасибо.

Aditya 10.01.2019 06:44

Спасибо @AdityaK! Этот также был хорошим объяснением * args

MattYYC 11.01.2019 01:01

Подобно другим предложениям, но, возможно, даже более изящно, если вам нравится рекурсия:

table = {'A':{'B':'2','C':{'D':'3'}}}
first = 'A'
second1 = 'B'
second2 = 'C'
third = 'D'


def get_from(x, *keys):
    return get_from(x[keys[0]], *keys[1:]) if len(keys) > 0 else x


print(get_from(table, first))
print(get_from(table, first, second1))
print(get_from(table, first, second2, third))

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

Или, если вы думаете, что короче - не всегда лучше:

def get_from(x, *keys):
    if len(keys) > 0 
        return get_from(x[keys[0]], *keys[1:])
    else:
        return x

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

Спасибо @Grismar - очень лаконично. Является ли [1:] эквивалентом popitems ()? Не уверен, что это значит.

MattYYC 11.01.2019 01:08
[1:] означает «все элементы из последовательности, начиная с элемента с индексом 1». Итак, для x = [1,2,3,4], x[1:] будет [2,3,4] - подробнее об этом здесь, называется «нарезка». pythoncentral.io/how-to-slice-listsarrays-and-tuples-in-pyth‌ на Это не эквивалент popitem(), не только потому, что он возвращает большую часть последовательности, но и, что более важно, потому что он не изменяет оригинал. - возвращает копию своего содержимого.
Grismar 11.01.2019 02:38

Другие вопросы по теме