Python: ubah defaultdict menjadi dict

90

Bagaimana cara mengonversi defaultdict

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

menjadi perintah umum?

{'2': ['a'], '3': ['b'], '1': ['b', 'a']}
pengguna2988464
sumber
10
dict(number_to_letter)
Tim Peters
2
@TimPeters karena ini sebenarnya adalah pertanyaan yang ditulis dengan bagus, dengan judul yang jelas (dan akan muncul dengan mudah dalam penelusuran), untuk referensi di masa mendatang, sebaiknya Anda meletakkannya sebagai jawaban jika kami tidak dapat menemukan penipu yang lebih baik .. .
Jon Clements
Jawaban ini akan membantu: stackoverflow.com/a/3031915/1628832
karthikr
1
@JonClements, bagus, tapi DSM sudah melakukannya - Saya harap jawabannya diterima :-)
Tim Peters
2
@TimPeters selamat atas 10k btw ... Saya merasa itu tidak akan memakan waktu lama - Anda harus (steker tak tahu malu) mampir ke chat.stackoverflow.com/rooms/6/python di beberapa titik :)
Jon Clements

Jawaban:

121

Anda cukup menelepon dict:

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

tapi ingat bahwa defaultdict adalah sebuah dict:

>>> isinstance(a, dict)
True

hanya dengan perilaku yang sedikit berbeda, ketika Anda mencoba mengakses kunci yang hilang - yang biasanya akan memunculkan KeyError- yang default_factorydipanggil sebagai gantinya:

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

Itulah yang Anda lihat saat Anda print a sebelum sisi data kamus muncul.

Jadi trik lain untuk mendapatkan kembali perilaku seperti diktik tanpa benar-benar membuat objek baru adalah dengan mengatur ulang 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

tetapi seringkali hal ini tidak sebanding dengan masalahnya.

DSM
sumber
Saya baru mulai belajar pemrograman dengan Python. Bisakah Anda menjelaskan lebih lanjut tentang cara menggunakan default_factory? Saya hanya tidak tahu apa yang sedang terjadi. Maaf.
pengguna2988464
Dan apa itu 'KeyError'?
pengguna2988464
4
@ user2988464: Anda sudah pernah menggunakan default_factory- itulah fungsi yang Anda berikan defaultdictsaat pertama kali membuat, seperti defaultdict(int)atau defaultdict(list). Setiap kali Anda mencoba mencari kunci di kamus, seperti a['3'], misalnya, dalam kamus biasa Anda akan mendapatkan nilainya atau memunculkan KeyErrorpengecualian (seperti kesalahan, memberi tahu Anda bahwa kunci itu tidak dapat ditemukan). Tapi di a defaultdict, itu malah memanggil default_factoryfungsi untuk membuat nilai default baru (itulah "default" di defaultdict) untuk Anda.
DSM
2
Bermanfaat untuk mencatat bahwa properti template .items Django tidak akan bekerja dengan defaultdict, itulah mengapa saya berakhir di sini! Jadi ada satu alasan bagus untuk pertobatan tersebut
Ben
2
Juga sangat membantu untuk dicatat bahwa pickle(untuk menyimpan objek python ke file) tidak dapat menangani defaultdicts dalam banyak keadaan .
drevicko
28

Jika defaultdict Anda ditentukan secara rekursif, misalnya:

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

cara sederhana lain untuk mengubah defaultdict kembali ke dict adalah dengan menggunakan jsonmodul

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

dan tentu saja, nilai yang dimuat dalam defaultdict Anda perlu dibatasi pada tipe data yang didukung json, tetapi seharusnya tidak menjadi masalah jika Anda tidak bermaksud untuk menyimpan kelas atau fungsi di dict.

meong
sumber
8
Ide bagus,
sayang
15

Jika Anda bahkan menginginkan versi rekursif untuk mengubah rekursif defaultdictmenjadi dictAnda dapat mencoba yang berikut:

#! /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
sumber
Itulah yang saya butuhkan! Sayangnya, defaultdict saya memiliki beberapa kunci yang tidak dapat diserialkan JSON tanpa pembuat enkode khusus (kuncinya adalah tupel - bukan pilihan saya, hanya masalah saya)
Kasapo
Bagus. Menggunakan pemahaman kamus singkat jika hanya dalam dua lapisan (yaitu defaultdict(lambda: defaultdict(int))): {k: dict(v) for k, v in foo.items()}
ggorlen