Prendiamo il codice eccellente da @karlknechtel e vedere che cosa fa:
>>> d = dict((m.get(k, k), v) for (k, v) in d.items())
{'gid': 3, 'group': 'ordinary users', 'uid': 1, 'user': 'user1'}
Ma come funziona?
Per creare un dizionario, è possibile utilizzare la funzione dict()
. Si aspetta una lista di tuple. In 3.xe> 2.7, è anche possibile utilizzare la comprensione del dizionario (vedere answer by @nightcracker).
Analizziamo l'argomento del ditt. All'inizio abbiamo bisogno di un elenco di tutti gli elementi in m. Ogni elemento è una tupla nel formato (chiave, valore).
>>> d.items()
[('group_id', 3), ('user_id', 1), ('user', 'user1'), ('group_name', 'ordinary users')]
dato un valore chiave k
, siamo riusciti a ottenere il valore della chiave giusta da m
facendo m[k]
.
>>> k = 'user_id'
>>> m[k]
'uid'
Purtroppo, non esistono anche tutte le chiavi in d
in m
.
>>> k = 'user'
>>> m[k]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'user'
Per aggirare questo, si può utilizzare d.get(x, y)
, che restituisce d[x]
se la chiave x
esiste, o il valore di default y
se non lo fa. Ora, se non esiste una chiaveda d
in m
, l'impostazione predefinita è .
>>> m.get(k, k).
'user'
Ora siamo pronti a costruire una lista di tuple di fornire ai dict()
. Per costruire una lista in una riga, possiamo usare list comprehension.
Per costruire un elenco di piazze, si potrebbe scrivere questo:
>>> [x**2 for x in range(5)]
[0, 1, 4, 9, 16]
Nel nostro caso, sembra che questo:
>>> [(m.get(k, k), v) for (k, v) in d.items()]
[('gid', 3), ('uid', 1), ('user', 'user1'), ('group', 'ordinary users')]
Questo è un boccone, diamo un'occhiata a che ancora una volta.
Dammi un elenco [...]
, che si compone di tuple:
[(.., ..) ...]
voglio una tupla per ogni elemento x
in d
:
[(.., ..) for x in d.items()]
Sappiamo che ogni elemento è una tupla con due componenti, quindi possiamo estenderlo a due variabili k
e v
.
[(.., ..) for (k, v) in d.items()]
Ogni tupla deve avere la giusta chiave da m come primo componente, oppure k se k non esiste in m, e il valore di d.
[(m.get(k, k), v) for (k, v) in d.items()]
Possiamo passarlo come argomento a dict()
.
>>> dict([(m.get(k, k), v) for (k, v) in d.items()])
{'gid': 3, 'group': 'ordinary users', 'uid': 1, 'user': 'user1'}
Sembra buono! Ma aspetta, potresti dire, @karlknechtel non ha usato parentesi quadre.
Giusto, non ha usato una comprensione di lista, ma uno generator expression. Semplicemente parlando, la differenza è che una lista di comprensione costruisce l'intera lista in memoria, mentre un'espressione di generatore calcola sull'oggetto alla volta. Se una lista su serve come risultato intermedio, di solito è una buona idea usare un'espressione di generatore. In questo esempio, non fa davvero la differenza, ma è una buona abitudine abituarsi.
Le espressioni generatore equivalenti aspetto:
>>> ((m.get(k, k), v) for (k, v) in d.items())
<generator object <genexpr> at 0x1004b61e0>
Se si passa un generatore di espressione come argomento di una funzione, di solito si può omettere le parentesi esterne. Infine, otteniamo:
>>> dict((m.get(k, k), v) for (k, v) in d.items())
{'gid': 3, 'group': 'ordinary users', 'uid': 1, 'user': 'user1'}
Accade molto in una riga di codice. Alcuni dicono che questo è illeggibile, ma una volta che vi siete abituati, allungare questo codice su più righe sembra illeggibile. Basta non esagerare. La comprensione delle liste e le espressioni generatrici sono molto potenti, ma con un grande potere derivano grandi responsabilità. +1 per una buona domanda!
Quale versione di python? – orlp
uid è il valore nel secondo, non nella chiave. Qual è l'output che ti piace vedere? –