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)?

StackOverflow https://stackoverflow.com/questions/230896

  •  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'])
Foi útil?

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.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top