Python: перетворити вирок за замовчуванням на dict


90

Як я можу конвертувати вирок за замовчуванням

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

бути загальним диктом?

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

10
dict(number_to_letter)
Тім Пітерс

2
@TimPeters, оскільки це насправді приємно написане запитання з очевидним заголовком (і воно має легко відображатися під час пошуку), для подальшого використання варто було б поставити це як відповідь, якщо ми не зможемо знайти дурня, який краще .. .
Джон Клементс

Відповідь на це питання має допомогти: stackoverflow.com/a/3031915/1628832
karthikr

1
@JonClements, хороша думка, але DSM це вже зробив - сподіваюся, його відповідь буде прийнято :-)
Тім Пітерс,

2
@TimPeters вітає 10 тис. До речі ... У мене було відчуття, що це не займе у вас багато часу - вам слід (безсоромна вилка) заскочити в 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']}

але пам’ятайте, що дефолт - це дикт:

>>> 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

але здебільшого це не варте клопоту.


я тільки починаю вчитися програмуванню за допомогою Python. Чи можете ви пояснити більше про те, як користуватися default_factory? Я просто не маю уявлення про те, що відбувається. Вибачте.
user2988464

А що таке "KeyError"?
user2988464

4
@ user2988464: ви вже використовували default_factory- це та функція, яку ви передали, коли зробили, defaultdictспочатку, наприклад defaultdict(int)або defaultdict(list). Всякий раз, коли ви намагаєтесь знайти ключ у словнику, як a['3'], наприклад, у звичайному словнику, ви або отримуєте значення, або воно викликає KeyErrorвиняток (наприклад, помилка, повідомляючи вам, що не вдалося знайти цей ключ). Але в a defaultdict, натомість вона викликає default_factoryфункцію, щоб зробити для вас нове значення за замовчуванням (це "значення за замовчуванням" defaultdict).
DSM

2
Корисно відзначити, що властивість шаблону .items від Django не працюватиме із замовчуванням, саме тому я опинився тут! Отже, є одна вагома причина для перетворення
Бен,

2
Також корисно зауважити, що pickle(для збереження об’єктів python у файл) не може обробляти defaultdicts за багатьох обставин .
drevicko

28

Якщо ваш вирок за замовчуванням визначений рекурсивно, наприклад:

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))

і, звичайно, значення, що містяться у вашому вироку за замовчуванням, повинні бути обмежені підтримуваними json типами даних, але це не повинно бути проблемою, якщо ви не маєте наміру зберігати класи або функції в дикті.


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)

Це саме те, що мені потрібно було! На жаль, у моєму замовчуванні є деякі ключі, які неможливо серіалізувати JSON без спеціального кодера (ключі кортежі - це не мій вибір, це лише моя проблема)
Kasapo

Хороший. Використання словника є стислим, якщо воно глибиною всього два шари (тобто defaultdict(lambda: defaultdict(int))): {k: dict(v) for k, v in foo.items()}
ggorlen
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.