Dada uma lista de nomes de variáveis em Python, como faço para criar um dicionário com os nomes das variáveis como chaves (para os valores das variáveis)?
-
04-07-2019 - |
Pergunta
Eu tenho uma lista de nomes de variáveis, assim:
['foo', 'bar', 'baz']
(Originalmente perguntei como converto uma lista de variáveis.Veja a resposta de Greg Hewgill abaixo.)
Como faço para converter isso em um dicionário onde as chaves são os nomes das variáveis (como strings) e os valores são os valores das variáveis?
{'foo': foo, 'bar': bar, 'baz': baz}
Agora que estou fazendo a pergunta novamente, pensei:
d = {}
for name in list_of_variable_names:
d[name] = eval(name)
Isso pode ser melhorado?
Atualizar, respondendo à pergunta (em um comentário) sobre por que eu gostaria de fazer isso:
Muitas vezes me pego usando o operador % para strings com um dicionário de nomes e valores para interpolar.Freqüentemente, os nomes na string são apenas nomes de variáveis locais.Então (com a resposta abaixo) posso fazer algo assim:
message = '''Name: %(name)s
ZIP: %(zip)s
Dear %(name)s,
...''' % dict((x, locals()[x]) for x in ['name', 'zip'])
Solução
Esqueça a filtragem locals()
!O dicionário que você fornece à string de formatação pode conter chaves não utilizadas:
>>> name = 'foo'
>>> zip = 123
>>> unused = 'whoops!'
>>> locals()
{'name': 'foo', 'zip': 123, ... 'unused': 'whoops!', ...}
>>> '%(name)s %(zip)i' % locals()
'foo 123'
Com o novo recurso f-string em Python 3.6, usando locals()
não é mais necessário:
>>> name = 'foo'
>>> zip = 123
>>> unused = 'whoops!'
>>> f'{zip: >5} {name.upper()}'
' 123 FOO'
Outras dicas
Sua lista original [foo, bar, baz]
não contém a variável nomes, ele contém apenas elementos que se referem ao mesmo valores como as variáveis que você listou.Isso ocorre porque você pode ter dois nomes de variáveis diferentes que se referem ao mesmo valor.
Portanto, a lista por si só não contém informações sobre quais outros nomes se referem aos objetos.O primeiro elemento do seu array tem o nome foo
mas também tem o nome a[0]
(assumindo que seu array seja chamado a
).Depois de executar o código a seguir, quux
também se refere ao mesmo objeto:
quux = a[0]
Atualizar:Você está certo que pode usar eval()
para isso, mas seu uso geralmente é desencorajado.Python fornece um membro especial chamado __dict__
que contém a tabela de símbolos do módulo atual.Então você pode:
import __main__
d = dict((x, __main__.__dict__[x]) for x in list_of_variable_names)
Ter de import __main__
quando seu código está no módulo principal sem nome é uma peculiaridade do Python.
Você pode usar compreensões de lista ou gerador para construir uma lista de tuplas de chave e valor usadas para instanciar diretamente um ditado.A melhor forma está abaixo:
dict((name, eval(name)) for name in list_of_variable_names)
Além disso, se você sabe, por exemplo, que as variáveis existem na tabela de símbolos locais, você pode se salvar do perigoso eval procurando a variável diretamente nos locais:
dict((name, locals()[name]) for name in list_of_variable_names)
Após sua atualização final, acho que a resposta abaixo é realmente o que você deseja.Se você estiver usando isso apenas para expansão de string com strings que você controla, basta passar locals() diretamente para a expansão de string e ela selecionará os valores desejados
Se, no entanto, essas strings pudessem vir de uma fonte externa (por exemplo,arquivos de tradução), então é uma boa ideia filtrar locais()
Não é eficiente, mas sem invocar eval
:
dict((k,v) for (k,v) in globals().iteritems() if k in list_of_variable_names)
ou
dict((k,v) for (k,v) in vars().iteritems() if k in list_of_variable_names)
dependendo do que você deseja.