Python: convertir defaultdict en dict

90

Comment puis-je convertir un defaultdict

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

être un dict commun?

{'2': ['a'], '3': ['b'], '1': ['b', 'a']}
user2988464
la source
10
dict(number_to_letter)
Tim Peters
2
@TimPeters puisqu'il s'agit en fait d'une question bien écrite, avec un titre évident (et devrait apparaître facilement dans les recherches), pour référence future, il vaudrait la peine de la mettre comme réponse si nous ne pouvons pas trouver une dupe qui est meilleure. .
Jon Clements
Cette réponse devrait aider: stackoverflow.com/a/3031915/1628832
karthikr
1
@JonClements, bon point, mais DSM l'a déjà fait - j'espère que sa réponse est acceptée :-)
Tim Peters
2
@TimPeters félicitations pour le 10k btw ... J'avais le sentiment que cela ne vous prendrait pas longtemps - vous devriez (plug sans vergogne) pop par chat.stackoverflow.com/rooms/6/python à un moment donné :)
Jon Clements

Réponses:

121

Vous pouvez simplement appeler dict:

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

mais rappelez-vous qu'un defaultdict est un dict:

>>> isinstance(a, dict)
True

juste avec un comportement légèrement différent, en ce que lorsque vous essayez d'accéder à une clé qui manque - ce qui soulèverait normalement un KeyError- le default_factoryest appelé à la place:

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

C'est ce que vous voyez lorsque vous voyez print ale côté données du dictionnaire apparaître.

Donc, une autre astuce pour obtenir un comportement plus dictlike sans créer un nouvel objet est de réinitialiser 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

mais la plupart du temps, cela ne vaut pas la peine.

DSM
la source
je commence juste à apprendre la programmation avec Python. Pouvez-vous expliquer plus sur comment utiliser default_factory? Je n'ai simplement aucune idée de ce qui se passe. Pardon.
user2988464
Et qu'est-ce que «KeyError»?
user2988464
4
@ user2988464: vous avez déjà utilisé default_factory- c'est la fonction que vous avez passée lorsque vous avez fait le defaultdicten premier lieu, comme defaultdict(int)ou defaultdict(list). Chaque fois que vous essayez de rechercher une clé dans le dictionnaire, comme a['3'], par exemple, dans un dictionnaire habituel, vous obtenez la valeur ou cela déclenche une KeyErrorexception (comme une erreur, vous indiquant qu'il n'a pas pu trouver cette clé). Mais dans a defaultdict, il appelle à la place la default_factoryfonction pour créer une nouvelle valeur par défaut (c'est la "valeur par défaut" defaultdict) pour vous.
DSM
2
Il est utile de noter que la propriété de modèle .items de Django ne fonctionnera pas avec defaultdict, c'est pourquoi je me suis retrouvé ici! Il y a donc une bonne raison pour la conversion
Ben
2
Il est également utile de noter que pickle(pour enregistrer des objets python dans un fichier) ne peut pas gérer les defaultdicts dans de nombreuses circonstances .
drevicko
28

Si votre defaultdict est défini de manière récursive, par exemple:

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

encore un autre moyen simple de reconvertir defaultdict en dict est d'utiliser le jsonmodule

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

et bien sûr, les valeurs contenues dans votre defaultdict doivent être confinées aux types de données pris en charge par json, mais cela ne devrait pas poser de problème si vous n'avez pas l'intention de stocker des classes ou des fonctions dans le dict.

Miaou
la source
8
Bonne idée, dommage que mes données ne
soient
15

Si vous voulez même une version récursive pour convertir un récursif defaultdicten un, dictvous pouvez essayer ce qui suit:

#! /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
la source
C'est exactement ce dont j'avais besoin! Malheureusement, mon defaultdict a des clés qui ne sont pas sérialisables JSON sans encodeur personnalisé (les clés sont des tuples - pas mon choix, juste mon problème)
Kasapo
Bon. L'utilisation d'une compréhension de dictionnaire est succincte si elle n'a que deux couches de profondeur (c'est-à-dire defaultdict(lambda: defaultdict(int))): {k: dict(v) for k, v in foo.items()}
ggorlen