Учитывая список имен переменных в Python, как мне создать словарь с именами переменных в качестве ключей (к значениям переменных)?
-
04-07-2019 - |
Вопрос
У меня есть список имен переменных, например:
['foo', 'bar', 'baz']
(Изначально я спросил, как преобразовать список переменных.См. ответ Грега Хьюгилла ниже.)
Как преобразовать это в словарь, где ключами являются имена переменных (в виде строк), а значениями являются значения переменных?
{'foo': foo, 'bar': bar, 'baz': baz}
Теперь, когда я снова задаю вопрос, я придумал:
d = {}
for name in list_of_variable_names:
d[name] = eval(name)
Можно ли это улучшить?
Обновлять, отвечая на вопрос (в комментарии) о том, почему я хочу это сделать:
Я часто использую оператор % для строк со словарем имен и значений для интерполяции.Часто имена в строке — это просто имена локальных переменных.Итак (с ответом ниже) я могу сделать что-то вроде этого:
message = '''Name: %(name)s
ZIP: %(zip)s
Dear %(name)s,
...''' % dict((x, locals()[x]) for x in ['name', 'zip'])
Решение
Забудьте о фильтрации locals ()
! Словарь, который вы задаете для строки форматирования, может содержать неиспользуемые ключи:
>>> name = 'foo'
>>> zip = 123
>>> unused = 'whoops!'
>>> locals()
{'name': 'foo', 'zip': 123, ... 'unused': 'whoops!', ...}
>>> '%(name)s %(zip)i' % locals()
'foo 123'
С новой функцией f-string в Python 3.6 с использованием locals ()
больше не требуется:
>>> name = 'foo'
>>> zip = 123
>>> unused = 'whoops!'
>>> f'{zip: >5} {name.upper()}'
' 123 FOO'
Другие советы
Ваш оригинальный список [foo, bar, baz]
не содержит переменную names , он просто содержит элементы, которые ссылаются на те же значения значений в качестве переменных, которые вы перечислили. Это потому, что вы можете иметь два разных имени переменной, которые ссылаются на одно и то же значение.
Таким образом, сам по себе список не содержит информации о том, какие другие имена относятся к объектам. Первый элемент в вашем массиве имеет имя foo
, но также имеет имя a [0]
(при условии, что ваш массив называется a
). После выполнения следующего кода quux
также ссылается на тот же объект:
quux = a[0]
Обновление: вы правы, что для этого можете использовать eval ()
, но его использование обычно не рекомендуется. Python предоставляет специального члена с именем __ dict __
которая содержит таблицу символов для текущего модуля. Так что вы можете:
import __main__
d = dict((x, __main__.__dict__[x]) for x in list_of_variable_names)
Необходимость импортировать __main __
, когда ваш код находится в неназванном главном модуле, - это особенность Python.
Вы можете использовать списки или генераторы для составления списка ключей, кортежей значений, используемых для непосредственного создания диктанта. Лучший способ ниже:
dict((name, eval(name)) for name in list_of_variable_names)
Кроме того, если вы, например, знаете, что переменные существуют в локальной таблице символов, вы можете спасти себя от опасного eval, посмотрев переменную непосредственно из локальных объектов:
dict((name, locals()[name]) for name in list_of_variable_names)
После вашего последнего обновления, я думаю, что ответ на этот вопрос действительно то, что вы хотите. Если вы просто используете это для раскрытия строк с помощью контролируемых вами строк, просто передайте locals () непосредственно в раскрытие строки, и он выберет нужные значения
Если, однако, эти строки могут когда-либо поступать из внешнего источника (например, файлы переводов), то лучше отфильтровать localals ()
Не эффективно, но без вызова eval
:
dict((k,v) for (k,v) in globals().iteritems() if k in list_of_variable_names)
или
dict((k,v) for (k,v) in vars().iteritems() if k in list_of_variable_names)
в зависимости от того, чего вы хотите.