Python: Konvertiere defaultdict in dict

90

Wie kann ich ein Standarddikt konvertieren?

number_to_letter
defaultdict(<class 'list'>, {'2': ['a'], '3': ['b'], '1': ['b', 'a']})

ein gemeinsames Diktat sein?

{'2': ['a'], '3': ['b'], '1': ['b', 'a']}
user2988464
quelle
10
dict(number_to_letter)
Tim Peters
2
@TimPeters Da dies eigentlich eine gut geschriebene Frage mit einem offensichtlichen Titel ist (und bei der Suche leicht auftauchen sollte), wäre es für zukünftige Referenzzwecke sinnvoll, dies als Antwort zu verwenden, wenn wir keinen besseren Betrüger finden können. .
Jon Clement
Diese Antwort sollte helfen: stackoverflow.com/a/3031915/1628832
karthikr
1
@ JonClements, guter Punkt, aber DSM hat es bereits getan - ich hoffe, seine Antwort wird akzeptiert :-)
Tim Peters
2
@ TimPeters Glückwunsch zu den 10k übrigens ... Ich hatte das Gefühl, es würde nicht lange dauern - du solltest (schamloser Plug) irgendwann bei chat.stackoverflow.com/rooms/6/python vorbeischauen :)
Jon Clements

Antworten:

121

Sie können einfach anrufen dict:

>>> a
defaultdict(<type 'list'>, {'1': ['b', 'a'], '3': ['b'], '2': ['a']})
>>> dict(a)
{'1': ['b', 'a'], '3': ['b'], '2': ['a']}

Aber denken Sie daran, dass ein Standarddikt ein Diktat ist :

>>> isinstance(a, dict)
True

Nur mit etwas anderem Verhalten, wenn Sie versuchen, auf einen Schlüssel zuzugreifen, der fehlt - was normalerweise einen auslösen würde KeyError-, default_factorywird stattdessen Folgendes aufgerufen:

>>> a.default_factory
<type 'list'>

Das sehen Sie, wenn Sie print avor der Datenseite des Wörterbuchs erscheinen.

Ein weiterer Trick, um ein diktatischeres Verhalten wiederherzustellen, ohne tatsächlich ein neues Objekt zu erstellen, ist das Zurücksetzen default_factory:

>>> a.default_factory = None
>>> a[4].append(10)
Traceback (most recent call last):
  File "<ipython-input-6-0721ca19bee1>", line 1, in <module>
    a[4].append(10)
KeyError: 4

Aber die meiste Zeit ist das die Mühe nicht wert.

DSM
quelle
Ich fange gerade an, Programmieren mit Python zu lernen. Können Sie mehr über die Verwendung erklären default_factory? Ich habe einfach keine Ahnung, was los ist. Es tut uns leid.
user2988464
Und was ist 'KeyError'?
user2988464
4
@ user2988464: Sie haben bereits verwendet default_factory- das ist die Funktion, die Sie übergeben haben, als Sie defaultdictdie erste gemacht haben, wie defaultdict(int)oder defaultdict(list). Wenn Sie versuchen, einen Schlüssel im Wörterbuch nachzuschlagen, wie a['3']zum Beispiel in einem normalen Wörterbuch, erhalten Sie entweder den Wert oder es wird eine KeyErrorAusnahme ausgelöst (wie ein Fehler, der Ihnen mitteilt, dass dieser Schlüssel nicht gefunden werden konnte). In a defaultdictwird stattdessen die default_factoryFunktion aufgerufen, um einen neuen Standardwert (das ist der "Standard" in defaultdict) für Sie festzulegen.
DSM
2
Es ist hilfreich zu beachten, dass die .items-Vorlageneigenschaft von Django nicht mit defaultdict funktioniert, weshalb ich hier gelandet bin! Es gibt also einen guten Grund für die Konvertierung
Ben
2
Es ist auch hilfreich zu beachten, dass pickle(zum Speichern von Python-Objekten in einer Datei) defaultdicts unter vielen Umständen nicht verarbeitet werden kann .
Drevicko
28

Wenn Ihr Standarddikt rekursiv definiert ist, zum Beispiel:

from collections import defaultdict
recurddict = lambda: defaultdict(recurddict)
data = recurddict()
data["hello"] = "world"
data["good"]["day"] = True

Eine weitere einfache Möglichkeit, defaultdict wieder in dict umzuwandeln, ist die Verwendung des jsonModuls

import json
data = json.loads(json.dumps(data))

und natürlich müssen die in Ihrem Standarddikt enthaltenen Werte auf von JSON unterstützte Datentypen beschränkt sein, aber es sollte kein Problem sein, wenn Sie nicht beabsichtigen, Klassen oder Funktionen im Diktat zu speichern.

Miau
quelle
8
Gute Idee, schade, dass meine Daten nicht in JSON serialisiert werden: * (
Kasapo
15

Wenn Sie sogar eine rekursive Version zum Konvertieren einer rekursiven defaultdictin eine möchten dict, können Sie Folgendes versuchen:

#! /usr/bin/env python3

from collections import defaultdict

def ddict():
    return defaultdict(ddict)

def ddict2dict(d):
    for k, v in d.items():
        if isinstance(v, dict):
            d[k] = ddict2dict(v)
    return dict(d)

myddict = ddict()

myddict["a"]["b"]["c"] = "value"

print(myddict)

mydict = ddict2dict(myddict)

print(mydict)
white_gecko
quelle
Genau das brauchte ich! Leider hat mein Standarddikt einige Schlüssel, die ohne einen benutzerdefinierten Encoder nicht JSON-serialisierbar sind (die Schlüssel sind Tupel - nicht meine Wahl, nur mein Problem)
Kasapo
Gut. Die Verwendung eines Wörterbuchverständnisses ist prägnant, wenn es nur zwei Schichten tief ist (dh defaultdict(lambda: defaultdict(int))): {k: dict(v) for k, v in foo.items()}
ggorlen