Dada una lista de nombres de variables en Python, ¿cómo puedo crear un diccionario con los nombres de las variables como claves (a los valores de las variables)?

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

  •  04-07-2019
  •  | 
  •  

Pregunta

Tengo una lista de nombres de variables, como esta:

['foo', 'bar', 'baz']

(Originalmente pregunté cómo convertir una lista de variables. Vea la respuesta de Greg Hewgill a continuación).

¿Cómo puedo convertir esto en un diccionario donde las claves son los nombres de las variables (como cadenas) y los valores son los valores de las variables?

{'foo': foo, 'bar': bar, 'baz': baz}

Ahora que estoy volviendo a hacer la pregunta, se me ocurrió:

d = {}
for name in list_of_variable_names:
    d[name] = eval(name)

¿Se puede mejorar eso?

Actualizar , respondiendo a la pregunta (en un comentario) de por qué me gustaría hacer esto:

A menudo me encuentro usando el operador% para cadenas con un diccionario de nombres y valores para interpolar. A menudo, los nombres en la cadena son solo los nombres de variables locales. Entonces (con la respuesta a continuación) puedo hacer algo como esto:

message = '''Name: %(name)s
ZIP: %(zip)s

Dear %(name)s,
...''' % dict((x, locals()[x]) for x in ['name', 'zip'])
¿Fue útil?

Solución

¡Olvídate de filtrar locals () ! El diccionario que le dé a la cadena de formato puede contener claves no utilizadas:

>>> name = 'foo'
>>> zip = 123
>>> unused = 'whoops!'
>>> locals()
{'name': 'foo', 'zip': 123, ... 'unused': 'whoops!', ...}
>>> '%(name)s %(zip)i' % locals()
'foo 123'

Con la nueva función f-string en Python 3.6, utilizando locals () ya no es necesario:

>>> name = 'foo'
>>> zip = 123
>>> unused = 'whoops!'
>>> f'{zip: >5} {name.upper()}'
'  123 FOO'

Otros consejos

Su lista original [foo, bar, baz] no contiene la variable names , solo contiene elementos que se refieren a los mismos valores de como las variables que listaste. Esto se debe a que puede tener dos nombres de variables diferentes que se refieren al mismo valor.

Por lo tanto, la lista por sí misma no contiene información sobre qué otros nombres se refieren a los objetos. El primer elemento de su matriz tiene el nombre foo pero también tiene el nombre a [0] (asumiendo que su matriz se llama a ). Después de ejecutar el siguiente código, quux también se refiere al mismo objeto:

quux = a[0]

Actualización: Tienes razón en que puedes usar eval () para eso, pero generalmente se desaconseja su uso. Python proporciona un miembro especial llamado __dict__ que contiene la tabla de símbolos para el módulo actual. Así que puedes:

import __main__
d = dict((x, __main__.__dict__[x]) for x in list_of_variable_names)

Tener que importar __main__ cuando su código está en el módulo principal sin nombre es una peculiaridad de Python.

Puede usar la lista o la comprensión del generador para construir una lista de tuplas de valor clave utilizadas para instanciar directamente un dict. La mejor manera es a continuación:

dict((name, eval(name)) for name in list_of_variable_names)

Además, si sabe, por ejemplo, que las variables existen en la tabla de símbolos locales, puede salvarse de la evaluación peligrosa mirando la variable directamente desde los locales:

dict((name, locals()[name]) for name in list_of_variable_names)

Después de tu actualización final, creo que la respuesta a continuación es realmente lo que quieres. Si solo estás usando esto para la expansión de cadenas con cadenas que controlas, simplemente pasa locals () directamente a la expansión de cadenas y seleccionará los valores deseados

Sin embargo, si estas cadenas pudieran provenir de una fuente externa (por ejemplo, archivos de traducción), entonces es una buena idea filtrar los locales ()

No eficiente, pero sin invocar eval :

dict((k,v) for (k,v) in globals().iteritems() if k in list_of_variable_names)

o

dict((k,v) for (k,v) in vars().iteritems() if k in list_of_variable_names)

dependiendo de lo que quieras.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top