Подтвердить что ты не робот

Разделите словарь на переменные

Я изучаю Python и в настоящее время участвую в изучении со словарями.

Мне было интересно:

Если у меня есть словарь вроде: d = {'key_1': 'value_a', 'key_2': 'value_b'}, и я хочу разделить/разделить этот словарь на переменные, где каждая переменная является ключом из словаря, и каждое значение переменной является значением этого ключа в словаре.

Каким будет лучший питонический способ достичь этого?

d = {'key_1': 'value_a', 'key_2': 'value_b'}
#perform the command and get
key_1 = 'value_a'
key_2 = 'value_b'

Я пробовал: key_1, key_2 = d но это не сработало.

В основном я ищу экспертную мудрость, чтобы узнать, есть ли лучший способ уменьшить 2 строки кода в один.

Примечание. Это не создание динамической переменной.

4b9b3361

Ответ 1

Проблема в том, что dicts неупорядочены, поэтому вы не можете использовать простую распаковку d.values(). Конечно, вы можете сначала отсортировать dict по ключу, а затем распаковать значения:

ds = sorted(d.items())
name0, name1, name2..., namen = [v[1] for v in ds]

Вы также можете, по крайней мере внутри объекта, сделать что-то вроде:

for k, v in dict.items():
    setattr(self, k, v)

Кроме того, как я уже упоминал в комментарии выше, если вы можете получить всю свою логику, которая нуждается в распакованном словаре, в качестве переменных в функцию, вы можете сделать:

def func(**kwargs):
    # Do stuff with labeled args

func(**d)

Ответ 2

Решение, о котором ранее не упоминалось, было бы

dictget = lambda d, *k: [d[i] for i in k]

а затем используйте его:

key_1, key_2 = dictget(d, 'key_1', 'key_2')

преимущество которого в том, что оно вполне читаемо даже при получении большего числа переменных.

Тем не менее, даже более читаемая была бы "реальной" функцией, такой как
def dictget(d, *k):
    """Get the values corresponding to the given keys in the provided dict."""
    return [d[i] for i in k]
    # or maybe
    return (d[i] for i in k) # if we suppose that we have bigger sets of result
    # or, equivalent to this
    for i in k:
        yield d[i]

который также поддерживает комментирование с помощью docstring и должен быть предпочтительным.

Ответ 3

Существующие ответы будут работать, но все они по существу повторно реализуют функцию, которая уже существует в стандартной библиотеке Python: operator.itemgetter()

Из документов:

Вернуть вызываемый объект, который выбирает элемент из своего операнда, используя метод операндов __getitem __(). Если указано несколько элементов, возвращает набор значений поиска. Например:

После f = itemgetter (2) вызов f (r) возвращает r [2].

После g = itemgetter (2, 5, 3) вызов g (r) возвращает (r [2], r [5], r [3]).


Другими словами, ваше деструктурированное диктовское назначение становится примерно таким:

from operator import itemgetter

d = {'key_1': 'value_a', 'key_2': 'value_b'}
key_1, key_2 = itemgetter('key_1', 'key_2')(d)

# prints "Key 1: value_a, Key 2: value_b"
print("Key 1: {}, Key 2: {}".format(key_1, key_2))

Ответ 4

У меня фактически есть usecase, где я вытаскиваю все аргументы метода __init__ в пространство имен self при построении объекта:

vars(self).update(somedict)

Функция vars дает вам определение "пространства имен", связанного с переданным объектом. Однако это не будет работать с locals в функции из-за деталей реализации CPython. Поэтому он не должен работать на всех переводчиков.

Для глобального пространства имен вы замените vars(self) на globals(), но это действительно признак того, что с вашей логикой что-то не так. Как сказано, для локальных переменных это не будет работать в любом случае (это будет NameError, даже если вы назначили значение dict).

Ответ 5

Вы можете сделать это, если вы храбры:

for k, v in d.items():
    locals()[k] = v

Но быть храбрым может быть недостаточно - вам также может быть безрассудно и т.д.

Если вы хотите быть безрассудным героем, как @ecatmur, вы можете сделать это:

locals().update(d)

Но теперь, когда ОП обновил свой вопрос и ответил на комментарии, похоже, это не то, что он действительно хочет сделать. Только для записи: есть веские причины для динамического создания переменных - даже если все здесь согласны с тем, что это не питонические. Многие проблемы стиля интерпретатора могут быть решены с помощью динамического изменения вашего объема. Просто делайте это контролируемым образом. И... э-э, не разворачивайте это на какой-то производственный сайт;)

Ответ 6

Я думаю, что это должно решить вашу проблему.

d = {'key_1': 'value_a', 'key_2': 'value_b'}
for k,v in d.items():
    exec '%s=%s'%(k,v)

Ответ 7

var1, var2 = (lambda key1, key2: (key1, key2))(**d)

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

Ответ 8

Не рекомендуется динамически объявлять переменные, потому что становится очень трудно найти источник имени переменной. Тем не менее, можно взломать решение Динамическое имя переменной в python, но я бы не рекомендовал его. Вероятно, лучше использовать простой старый словарь.

Ответ 9

Вот решение, которое использует модуль проверки Python в кадре стека вызова, чтобы определить, как извлечь правильные значения из предоставленного словаря. Прямо сейчас единственная проверка состоит в том, чтобы удостовериться, что есть значение, доступное для каждой из выходных переменных, но не стесняйтесь добавлять дополнительные проверки, если они вам нужны.

import inspect
def update(src):
    result = []
    cprev = inspect.currentframe().f_back
    #print(cprev.f_code.co_names)
    for v in cprev.f_code.co_names[1:]:
        if src is cprev.f_locals[v]: continue
        if v in src:
            result.append(src[v])
        else:
            raise NameError(v + " has no source for update")
    return result

Использование выглядит так:

src={'a': 1, 'b': 2, 'c': 3}
a,b,c = update(src)