Разделите словарь на переменные
Я изучаю 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 строки кода в один.
Примечание. Это не создание динамической переменной.
Ответы
Ответ 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)