2014-10-14 19 views
29

Gibt es eine elegantere Möglichkeit, diesen Code zu schreiben?Anhängen an Liste in Python-Wörterbuch

Was ich mache: Ich habe Schlüssel und Daten. Es kann eine Reihe von Daten geben, die einem Schlüssel zugewiesen sind, und deshalb erstelle ich ein Wörterbuch mit Listen von Daten, um dies darzustellen. Der folgende Code funktioniert gut, aber ich habe auf eine elegantere und pythonischer Methode gehofft.

dates_dict = dict() 
for key, date in cur: 
    if key in dates_dict: 
     dates_dict[key].append(date) 
    else: 
     dates_dict[key] = [date] 

Ich habe erwartet, dass die unten funktioniert, aber ich bekomme immer eine NoneType hat kein Attribut append Fehler.

dates_dict = dict() 
for key, date in cur: 
    dates_dict[key] = dates_dict.get(key, []).append(date) 

Das hat wahrscheinlich etwas mit der Tatsache zu tun, dass

print([].append(1)) 
None 

aber warum?

+2

Sie sollten in aussehen [ 'collections.defaultdict'] (https://docs.python.org/2/library/collections.html#collections.defaultdict) – CoryKramer

+0

Sie können versuchen, extend() anstelle von append() – weefwefwqg3

Antwort

48

list.append kehrt None, da es sich um eine in-Place-Operation ist und Sie es zurück zu dates_dict[key] zuweisen. Also, das nächste Mal, wenn Sie dates_dict.get(key, []).append tun, tun Sie tatsächlich None.append. Deshalb versagt es. Stattdessen können Sie einfach tun

dates_dict.setdefault(key, []).append(date) 

Aber wir haben collections.defaultdict nur für diesen Zweck. Sie können ein neues Listenobjekt Das schaffen so etwas wie diese

from collections import defaultdict 
dates_dict = defaultdict(list) 
for key, date in cur: 
    dates_dict[key].append(date) 

tun, wenn die key nicht im Wörterbuch zu finden ist.

Hinweis: Seit der defaultdict wird eine neue Liste erstellen, wenn der Schlüssel nicht im Wörterbuch gefunden wird, wird diese unbeabsichtigte Nebenwirkungen haben. Wenn Sie beispielsweise einfach einen Wert für den Schlüssel abrufen möchten, der nicht vorhanden ist, wird eine neue Liste erstellt und zurückgegeben.

+1

@chepner: Beachten Sie, dass '__missing __()' für keine Operationen neben '__getitem __()' aufgerufen wird. Dies bedeutet, dass 'get()', wie normale Wörterbücher, 'None' als Standard zurückgibt, anstatt' default_factory' zu verwenden, dh 'key in dates_dict' und' dates_dict.get (key) 'funktionieren wie erwartet – jfs

+0

Nur als a nachverfolgen.Am Ende habe ich setdefault benutzt, um mir genau das zu geben, was ich wollte, ohne einen zusätzlichen Import. Danke für die Hilfe –

+0

Ihre Erklärung, warum '[] .append' 'None' zurückgibt, macht für mich keinen Sinn. Wenn Sie es sofort zuweisen oder drucken, warum ist es dann wichtig, dass es sich um eine In-Place-Operation handelt? Warum sollte 'dates_dict.get (key, []). Append' yield' None' ergeben, außer 'dates_dict [key] == None'? – cfwschmidt

2

dates_dict[key] = dates_dict.get(key, []).append(date) setzt dates_dict[key] zu None als list.append gibt None zurück.

In [5]: l = [1,2,3] 

In [6]: var = l.append(3) 

In [7]: print var 
None 

sollten Sie collections.defaultdict verwenden

import collections 
dates_dict = collections.defaultdict(list) 
+0

Ja, das ist, was ich dachte. Da kein Wert zurückgegeben wird. Es wird None als Standard zurückgegeben. Danke –

+0

@MichaelMurphy, mit defaultdict wird der effizienteste Weg, um das zu tun, was Sie wollen –

11

Gibt es eine elegantere Art, diesen Code zu schreiben?

Verwendung collections.defaultdict:

from collections import defaultdict 

dates_dict = defaultdict(list) 
for key, date in cur: 
    dates_dict[key].append(date)