Python: przekonwertuj defaultdict na dict

90

Jak mogę przekonwertować plik defaultdict

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

być powszechnym nakazem?

{'2': ['a'], '3': ['b'], '1': ['b', 'a']}
user2988464
źródło
10
dict(number_to_letter)
Tim Peters,
2
@TimPeters, ponieważ jest to właściwie ładnie napisane pytanie, z oczywistym tytułem (i powinno łatwo pojawiać się w wynikach wyszukiwania), dla przyszłego odniesienia warto byłoby podać to jako odpowiedź, jeśli nie możemy znaleźć lepszego naiwnego ... .
Jon Clements
Ta odpowiedź powinna pomóc: stackoverflow.com/a/3031915/1628832
karthikr
1
@JonClements, słuszna uwaga, ale DSM już to zrobił - mam nadzieję, że jego odpowiedź została zaakceptowana :-)
Tim Peters
2
@TimPeters gratuluję 10 tysięcy btw ... Miałem przeczucie, że nie zajmie ci to dużo czasu - powinieneś (bezwstydna wtyczka) pop przez chat.stackoverflow.com/rooms/6/python w pewnym momencie :)
Jon Clements

Odpowiedzi:

121

Możesz po prostu zadzwonić dict:

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

ale pamiętaj, że defaultdict to dict:

>>> isinstance(a, dict)
True

tylko z nieco innym zachowaniem, polegającym na tym, że gdy próbujesz uzyskać dostęp do brakującego klucza - co zwykle spowodowałoby podniesienie a KeyError- default_factoryzamiast tego wywoływana jest:

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

To właśnie widzisz, print azanim pojawi się strona danych słownika.

Więc kolejną sztuczką, aby odzyskać bardziej dyktanda bez tworzenia nowego obiektu, jest zresetowanie 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

ale w większości przypadków nie jest to warte zachodu.

DSM
źródło
dopiero zaczynam uczyć się programowania w Pythonie. Czy możesz wyjaśnić więcej o tym, jak używać default_factory? Po prostu nie mam pojęcia, co się dzieje. Przepraszam.
user2988464
A co to jest „KeyError”?
user2988464
4
@ user2988464: już użyłeś default_factory- jest to funkcja, którą przekazałeś, kiedy tworzyłeś defaultdictw pierwszej kolejności, na przykład defaultdict(int)lub defaultdict(list). Za każdym razem, gdy próbujesz wyszukać klucz w słowniku, a['3']na przykład w zwykłym słowniku, albo dostajesz wartość, albo zgłasza KeyErrorwyjątek (jak błąd, informujący, że nie może znaleźć tego klucza). Ale w a defaultdictzamiast tego wywołuje default_factoryfunkcję, aby utworzyć nową wartość domyślną (to jest „domyślna” w defaultdict) dla Ciebie.
DSM
2
Warto zauważyć, że właściwość szablonu .items Django nie będzie działać z defaultdict, dlatego właśnie tutaj trafiłem! Jest więc jeden dobry powód do konwersji
Ben
2
Warto również zauważyć, że pickle(do zapisywania obiektów Pythona do pliku) defaultdictw wielu przypadkach nie obsługuje plików s .
drevicko
28

Jeśli Twój defaultdict jest zdefiniowany rekurencyjnie, na przykład:

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

jeszcze innym prostym sposobem na konwersję defaultdict z powrotem do dict jest użycie jsonmodule

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

i oczywiście wartości zawarte w twoim defaultdict muszą być ograniczone do obsługiwanych przez json typów danych, ale nie powinno to stanowić problemu, jeśli nie zamierzasz przechowywać klas lub funkcji w dict.

Miauczeć
źródło
8
Dobry pomysł, szkoda, że ​​moje dane nie zostaną serializowane do JSON: * (
Kasapo
15

Jeśli nawet potrzebujesz wersji rekurencyjnej do konwersji rekurencyjnej defaultdictna a dict, możesz spróbować następujących rozwiązań:

#! /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
źródło
Właśnie tego potrzebowałem! Niestety, mój defaultdict ma kilka kluczy, których nie można serializować w formacie JSON bez niestandardowego kodera (klucze to krotki - nie mój wybór, tylko mój problem)
Kasapo
Dobry. Używanie rozumienia słownikowego jest zwięzłe, jeśli ma tylko dwie warstwy głębokości (tj. defaultdict(lambda: defaultdict(int))): {k: dict(v) for k, v in foo.items()}
ggorlen