Dato un elenco di nomi di variabili in Python, come posso creare un dizionario con i nomi delle variabili come chiavi (ai valori delle variabili)?

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

  •  04-07-2019
  •  | 
  •  

Domanda

Ho un elenco di nomi di variabili, come questo:

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

(Inizialmente avevo chiesto come convertire un elenco di variabili. Vedi la risposta di Greg Hewgill di seguito.)

Come posso convertirlo in un dizionario in cui le chiavi sono i nomi delle variabili (come stringhe) e i valori sono i valori delle variabili?

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

Ora che sto ripetendo la domanda, ho pensato a:

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

Può essere migliorato?

Aggiorna , rispondendo alla domanda (in un commento) sul perché vorrei farlo:

Mi trovo spesso a usare l'operatore% per stringhe con un dizionario di nomi e valori da interpolare. Spesso i nomi nella stringa sono solo i nomi delle variabili locali. Quindi (con la risposta di seguito) posso fare qualcosa del genere:

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

Dear %(name)s,
...''' % dict((x, locals()[x]) for x in ['name', 'zip'])
È stato utile?

Soluzione

Dimentica il filtro locals () ! Il dizionario fornito alla stringa di formattazione può contenere chiavi non utilizzate:

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

Con la nuova funzione f-string in Python 3.6, usando locals () non è più necessario:

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

Altri suggerimenti

Il tuo elenco originale [foo, bar, baz] non contiene la variabile nomi , contiene solo elementi che fanno riferimento agli stessi valori come variabili che hai elencato. Questo perché puoi avere due nomi di variabili diversi che fanno riferimento allo stesso valore.

Quindi, l'elenco da solo non contiene informazioni su quali altri nomi si riferiscono agli oggetti. Il primo elemento nel tuo array ha il nome foo ma ha anche il nome a [0] (supponendo che il tuo array sia chiamato a ). Dopo aver eseguito il codice seguente, quux fa riferimento anche allo stesso oggetto:

quux = a[0]

Aggiornamento: hai ragione, puoi usare eval () , ma il suo uso è generalmente sconsigliato. Python fornisce un membro speciale chiamato __dict__ che contiene la tabella dei simboli per il modulo corrente. Quindi puoi:

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

Dover importare __main__ quando il tuo codice è nel modulo principale senza nome è una stranezza di Python.

È possibile utilizzare la comprensione dell'elenco o del generatore per creare un elenco di tuple chiave e di valore utilizzate per creare un'istanza diretta di un dict. Il modo migliore è di seguito:

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

Inoltre, se sai, ad esempio, che le variabili esistono nella tabella dei simboli locali, puoi salvarti dalla valutazione pericolosa guardando la variabile direttamente dalla gente del posto:

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

Dopo il tuo ultimo aggiornamento, penso che la risposta qui sotto sia davvero ciò che desideri. Se lo stai usando solo per l'espansione della stringa con le stringhe che controlli, passa i locali () direttamente all'espansione della stringa e sceglierà i valori desiderati

Se, tuttavia, queste stringhe potrebbero mai provenire da una fonte esterna (ad esempio file di traduzione), allora è una buona idea filtrare i locali ()

Non efficiente, ma senza invocare 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)

a seconda di ciò che vuoi.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top