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']}

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.


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.


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)

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
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.