Python: converti defaultdict in dict


93

Come posso convertire un file defaultdict

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

essere un dict comune?

{'2': ['a'], '3': ['b'], '1': ['b', 'a']}

11
dict(number_to_letter)
Tim Peters

2
@TimPeters poiché questa è in realtà una domanda ben scritta, con un titolo ovvio (e dovrebbe apparire facilmente nelle ricerche), per riferimento futuro varrebbe la pena metterla come risposta se non riusciamo a trovare un duplicato che sia meglio .. .
Jon Clements

Questa risposta dovrebbe aiutare: stackoverflow.com/a/3031915/1628832
karthikr

1
@ JonClements, buon punto, ma DSM lo ha già fatto - spero che la sua risposta sia accettata :-)
Tim Peters

2
@TimPeters congratulazioni per i 10k btw ... Avevo la sensazione che non ci sarebbe voluto molto - dovresti (plug spudorato) fare un salto da chat.stackoverflow.com/rooms/6/python ad un certo punto :)
Jon Clements

Risposte:


124

Puoi semplicemente chiamare dict:

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

ma ricorda che un defaultdict è un dict:

>>> isinstance(a, dict)
True

solo con un comportamento leggermente diverso, in quanto quando provi ad accedere a una chiave che manca - che normalmente solleverebbe a KeyError- default_factoryviene invece chiamato:

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

Questo è quello che vedi quando ti trovi print aprima che appaia il lato dati del dizionario.

Quindi un altro trucco per ottenere un comportamento più dictlike senza effettivamente creare un nuovo oggetto è ripristinare 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

ma il più delle volte questo non vale la pena.


Ho appena iniziato a imparare a programmare con Python. Puoi spiegare di più su come utilizzare default_factory? Non ho la più pallida idea di cosa stia succedendo. Scusate.
user2988464

E cos'è "KeyError"?
user2988464

5
@ user2988464: hai già usato default_factory- questa è la funzione che hai passato quando hai creato defaultdictil primo posto, come defaultdict(int)o defaultdict(list). Ogni volta che provi a cercare una chiave nel dizionario, come a['3'], ad esempio, in un normale dizionario o ottieni il valore o solleva KeyErrorun'eccezione (come un errore, che ti dice che non è riuscito a trovare quella chiave). Ma in a defaultdict, chiama invece la default_factoryfunzione per creare un nuovo valore predefinito (che è il "predefinito" in defaultdict) per te.
DSM

3
È utile notare che la proprietà del modello .items di Django non funziona con defaultdict, motivo per cui sono finito qui! Quindi c'è una buona ragione per la conversione
Ben

2
Utile anche notare che pickle(per salvare oggetti python in un file) non può gestire defaultdicti messaggi di posta elettronica in molte circostanze .
drevicko

28

Se il tuo defaultdict è definito in modo ricorsivo, ad esempio:

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

un altro modo semplice per riconvertire defaultdict in dict è usare jsonmodule

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

e, naturalmente, i valori contenuti nel tuo defaultdict devono essere limitati ai tipi di dati supportati da json, ma non dovrebbe essere un problema se non intendi memorizzare classi o funzioni nel dict.


9
Buona idea,
peccato che i

15

Se vuoi anche una versione ricorsiva per convertire un ricorsivo defaultdictin un dictpuoi provare quanto segue:

#! /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)

È esattamente quello di cui avevo bisogno! Sfortunatamente, il mio defaultdict ha alcune chiavi che non sono serializzabili JSON senza un codificatore personalizzato (le chiavi sono tuple - non una mia scelta, solo un mio problema)
Kasapo

1
Bene. L'uso di una comprensione del dizionario è succinto se è profondo solo due strati (cioè defaultdict(lambda: defaultdict(int))): {k: dict(v) for k, v in foo.items()}
ggorlen
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.