Python: преобразовать defaultdict в dict

90

Как я могу преобразовать defaultdict

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

быть общим изречением?

{'2': ['a'], '3': ['b'], '1': ['b', 'a']}
user2988464
источник
10
dict(number_to_letter)
Тим Питерс
2
@TimPeters, так как это на самом деле красиво написанный вопрос с очевидным заголовком (и должен легко отображаться при поиске), для справки в будущем стоит поставить его в качестве ответа, если мы не сможем найти обман, который лучше .. .
Джон Клементс
Этот ответ должен помочь: stackoverflow.com/a/3031915/1628832
karthikr 06
1
@JonClements, хорошая мысль, но DSM уже сделал - надеюсь, его ответ будет принят :-)
Тим Питерс
2
@TimPeters поздравляет вас с 10k btw ... У меня было чувство, что это не займет у вас много времени - вы должны (бесстыдный плагин) в какой-то момент заглянуть на chat.stackoverflow.com/rooms/6/python :)
Джон Клементс

Ответы:

121

Вы можете просто позвонить dict:

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

но помните, что defaultdict - это dict:

>>> isinstance(a, dict)
True

просто с немного другим поведением, когда вы пытаетесь получить доступ к отсутствующему ключу - который обычно вызывает a KeyError- default_factoryвместо этого вызывается:

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

Это то, что вы видите print aперед тем, как появится часть словаря с данными.

Итак, еще один трюк, чтобы вернуть более диктоподобное поведение без фактического создания нового объекта, - это сбросить 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

но в большинстве случаев это того не стоит.

DSM
источник
Я только начинаю изучать программирование на Python. Вы можете подробнее объяснить, как пользоваться default_factory? Я просто понятия не имею, что происходит. Сожалею.
user2988464 06
А что такое KeyError?
user2988464 06
4
@ user2988464: вы уже использовали default_factory- это функция, которую вы передали при создании defaultdictв первую очередь, например defaultdict(int)или defaultdict(list). Всякий раз, когда вы пытаетесь найти ключ в словаре, как a['3'], например, в обычном словаре, вы либо получаете значение, либо возникает KeyErrorисключение (например, ошибка, говорящая вам, что не удалось найти этот ключ). Но в a defaultdictон вместо этого вызывает default_factoryфункцию, чтобы установить для вас новое значение по умолчанию (это «default» в defaultdict).
DSM
2
Полезно отметить, что свойство шаблона Django .items не будет работать с defaultdict, поэтому я оказался здесь! Так что есть одна веская причина для обращения
Бен
2
Также полезно отметить, что pickle(для сохранения объектов Python в файл) не может обрабатывать defaultdicts во многих случаях .
drevicko
28

Если ваш defaultdict определен рекурсивно, например:

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

еще один простой способ преобразовать defaultdict обратно в dict - использовать jsonмодуль

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

и, конечно же, значения, содержащиеся в вашем defaultdict, должны быть ограничены поддерживаемыми json типами данных, но это не должно быть проблемой, если вы не собираетесь хранить классы или функции в dict.

мяу
источник
8
Хорошая идея, жаль, что мои данные не будут сериализованы в JSON: * (
Kasapo
15

Если вам даже нужна рекурсивная версия для преобразования рекурсивной defaultdictверсии в a, dictвы можете попробовать следующее:

#! /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
источник
Это именно то, что мне было нужно! К сожалению, в моем defaultdict есть некоторые ключи, которые нельзя сериализовать в формате JSON без специального кодировщика (ключи представляют собой кортежи - не мой выбор, просто моя проблема)
Kasapo
Хороший. Использование словарного понимания будет кратким, если оно всего на два уровня (то есть defaultdict(lambda: defaultdict(int))): {k: dict(v) for k, v in foo.items()}
ggorlen