2013-03-20 10 views
27

Questo mi stava causando un po 'di dolore ...dict.fromkeys puntano tutti alla stessa lista

ho creato un dizionario da un elenco

l = ['a','b','c'] 
d = dict.fromkeys(l, [0,0]) # initializing dictionary with [0,0] as values 

d['a'] is d['b'] # returns True 

Come posso fare ogni valore del dizionario un lista separata? Questo è possibile senza iterare su tutte le chiavi e impostandole uguali a un elenco? Mi piacerebbe modificare una lista senza cambiare tutte le altre.

risposta

25

si potrebbe utilizzare una comprensione dict:

>>> keys = ['a','b','c'] 
>>> value = [0, 0] 
>>> {key: list(value) for key in keys} 
    {'a': [0, 0], 'b': [0, 0], 'c': [0, 0]} 
+1

'list (value)' è la stessa cosa di 'value [:]' qui? – Droogans

+1

@Droogans: Sì. Trovo semplicemente brutta la notazione a slice vuota. – Blender

6

È possibile utilizzare questo:

l = ['a', 'b', 'c'] 
d = dict((k, [0, 0]) for k in l) 
2
l = ['a','b','c'] 
d = dict((i, [0, 0]) for i in l) 
-4
keys = ['a','b','c'] 
value = [0, 0] 
d = dict.fromkeys(keys,value) 
print d 
# {'a':[0, 0], 'b':[0, 0], 'c':[0, 0]} 
+0

Benvenuti in Stack Overflow! Sebbene questo codice possa rispondere alla domanda, fornire un contesto aggiuntivo sul perché e/o su come risponde alla domanda migliorerebbe significativamente il suo valore a lungo termine. Per favore [modifica] la tua risposta per aggiungere qualche spiegazione. – CodeMouse92

+0

Questa risposta non funziona. Prova 'd ['a'] is d ['b']' e vedrai che è ancora 'True', il che significa che puntano tutti allo stesso array. Le altre risposte sono corrette perché ogni chiave ha una copia distinta dell'array –

4

Questa risposta è qui per spiegare questo comportamento a chiunque flummoxed dai risultati ottengono di provare a istanziare un dict con fromkeys() con un valore predefinito mutabile in quello dict.

consideri:

#Python 3.4.3 (default, Nov 17 2016, 01:08:31) 

# start by validating that different variables pointing to an 
# empty mutable are indeed different references. 
>>> l1 = [] 
>>> l2 = [] 
>>> id(l1) 
140150323815176 
>>> id(l2) 
140150324024968 

così qualsiasi modifica l1 non influenzerà l2 e viceversa. questo sarebbe vero per qualsiasi mutevole finora, tra cui uno dict.

# create a new dict from an iterable of keys 
>>> dict1 = dict.fromkeys(['a', 'b', 'c'], []) 
>>> dict1 
{'c': [], 'b': [], 'a': []} 

questa può essere una comoda funzione. qui stiamo assegnando ad ogni chiave un valore di default che capita anche di essere una lista vuota.

# the dict has its own id. 
>>> id(dict1) 
140150327601160 

# but look at the ids of the values. 
>>> id(dict1['a']) 
140150323816328 
>>> id(dict1['b']) 
140150323816328 
>>> id(dict1['c']) 
140150323816328 

In effetti utilizzano tutti lo stesso riferimento! Una modifica a una è una modifica a tutti, poiché sono in effetti lo stesso oggetto!

>>> dict1['a'].append('apples') 
>>> dict1 
{'c': ['apples'], 'b': ['apples'], 'a': ['apples']} 
>>> id(dict1['a']) 
>>> 140150323816328 
>>> id(dict1['b']) 
140150323816328 
>>> id(dict1['c']) 
140150323816328 

per molti, questo non era ciò che era previsto!

Ora proviamo a fare una copia esplicita dell'elenco utilizzato come valore predefinito.

>>> empty_list = [] 
>>> id(empty_list) 
140150324169864 

e ora creare un dict con una copia della empty_list.

>>> dict2 = dict.fromkeys(['a', 'b', 'c'], empty_list[:]) 
>>> id(dict2) 
140150323831432 
>>> id(dict2['a']) 
140150327184328 
>>> id(dict2['b']) 
140150327184328 
>>> id(dict2['c']) 
140150327184328 
>>> dict2['a'].append('apples') 
>>> dict2 
{'c': ['apples'], 'b': ['apples'], 'a': ['apples']} 

Ancora nessuna gioia! Ho sentito qualcuno gridare, è perché ho usato una lista vuota!

>>> not_empty_list = [0] 
>>> dict3 = dict.fromkeys(['a', 'b', 'c'], not_empty_list[:]) 
>>> dict3 
{'c': [0], 'b': [0], 'a': [0]} 
>>> dict3['a'].append('apples') 
>>> dict3 
{'c': [0, 'apples'], 'b': [0, 'apples'], 'a': [0, 'apples']} 

Il comportamento predefinito di fromkeys() è assegnare None al valore.

>>> dict4 = dict.fromkeys(['a', 'b', 'c']) 
>>> dict4 
{'c': None, 'b': None, 'a': None} 
>>> id(dict4['a']) 
9901984 
>>> id(dict4['b']) 
9901984 
>>> id(dict4['c']) 
9901984 

Infatti, tutti i valori sono gli stessi (e l'unico!) None. Ora, ripetiamo, in una miriade di modi, attraverso il dict e cambia il valore.

>>> for k, _ in dict4.items(): 
... dict4[k] = [] 

>>> dict4 
{'c': [], 'b': [], 'a': []} 

Hmm. Sembra lo stesso di prima!

>>> id(dict4['a']) 
140150318876488 
>>> id(dict4['b']) 
140150324122824 
>>> id(dict4['c']) 
140150294277576 
>>> dict4['a'].append('apples') 
>>> dict4 
>>> {'c': [], 'b': [], 'a': ['apples']} 

Ma sono effettivamente diverse [] s, che è stato in questo caso il risultato desiderato.

+0

Quindi dobbiamo iterare? – user1712447

Problemi correlati