Python: แปลง defaultdict เป็น dict


93

ฉันจะแปลง defaultdict ได้อย่างไร

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

เป็นคำสั่งทั่วไป?

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

11
dict(number_to_letter)
Tim Peters

2
@TimPeters เนื่องจากนี่เป็นคำถามที่เขียนขึ้นอย่างสวยงามโดยมีชื่อเรื่องที่ชัดเจน (และควรปรากฏในการค้นหาได้ง่าย) สำหรับการอ้างอิงในอนาคตมันก็คุ้มค่าที่จะใส่เป็นคำตอบหากเราไม่สามารถหาคนหลอกลวงที่ดีกว่าได้ .. .
Jon Clements

คำตอบนี้น่าจะช่วยได้: stackoverflow.com/a/3031915/1628832
karthikr

1
@JonClements จุดที่ดี แต่ DSM ทำไปแล้ว - ฉันหวังว่าคำตอบของเขาจะเป็นที่ยอมรับ :-)
Tim Peters

2
@TimPeters ขอแสดงความยินดีกับ 10k btw ... ฉันรู้สึกว่ามันใช้เวลาไม่นาน - คุณควร (ปลั๊กไร้ยางอาย) ปรากฏโดยchat.stackoverflow.com/rooms/6/pythonในบางจุด :)
จอนเคลเมนต์

คำตอบ:


124

คุณสามารถโทร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

แต่ส่วนใหญ่แล้วสิ่งนี้ไม่คุ้มกับปัญหา


ฉันเพิ่งเริ่มเรียนรู้การเขียนโปรแกรมด้วย Python คุณสามารถอธิบายเพิ่มเติมเกี่ยวกับวิธีการใช้งานได้default_factoryหรือไม่? ฉันไม่รู้ว่าเกิดอะไรขึ้น ขออภัย.
user2988464

และ 'KeyError' คืออะไร?
user2988464

5
@ user2988464: คุณเคยใช้แล้วdefault_factory- ที่ฟังก์ชั่นที่คุณผ่านไปเมื่อคุณทำdefaultdictในสถานที่แรกเหมือนหรือdefaultdict(int) defaultdict(list)เมื่อใดก็ตามที่คุณพยายามค้นหาคีย์ในพจนานุกรมa['3']เช่นในพจนานุกรมปกติคุณจะได้รับค่านั้นหรือมีKeyErrorข้อยกเว้น (เช่นข้อผิดพลาดที่บอกคุณว่าไม่พบคีย์นั้น) แต่ในทางกลับdefaultdictกันจะเรียกใช้default_factoryฟังก์ชันเพื่อสร้างค่าเริ่มต้นใหม่ (นั่นคือ "ค่าเริ่มต้น" ในdefaultdict) ให้กับคุณ
DSM

3
โปรดทราบว่าคุณสมบัติเทมเพลต. item ของ Django จะไม่ทำงานกับ defaultdict ซึ่งเป็นเหตุผลว่าทำไมฉันถึงมาอยู่ที่นี่! ดังนั้นจึงมีเหตุผลที่ดีประการหนึ่งสำหรับการเปลี่ยนใจเลื่อมใส
เบ็น

2
นอกจากนี้ยังเป็นประโยชน์ที่จะทราบว่าpickle(สำหรับการบันทึกวัตถุหลามไปยังแฟ้ม) ไม่สามารถจัดการdefaultdictในหลายกรณี
drevicko

28

หาก defaultdict ของคุณถูกกำหนดแบบวนซ้ำตัวอย่างเช่น:

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

อีกวิธีง่ายๆในการแปลง defaultdict กลับเป็น dict คือการใช้jsonmodule

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

และแน่นอนว่าค่าที่อยู่ใน defaultdict ของคุณจะต้อง จำกัด เฉพาะประเภทข้อมูลที่รองรับโดย json แต่ก็ไม่ควรเป็นปัญหาหากคุณไม่ได้ตั้งใจที่จะจัดเก็บคลาสหรือฟังก์ชันไว้ใน dict


9
ความคิดที่ดีแย่เกินไปที่ข้อมูลของฉันจะไม่ต่ออนุกรมกับ JSON: * (
Kasapo

15

ถ้าคุณยังต้องการรุ่น recursive สำหรับการแปลง recursive defaultdictไป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)

นั่นคือสิ่งที่ฉันต้องการ! น่าเสียดายที่ defaultdict ของฉันมีคีย์บางตัวที่ไม่สามารถต่ออนุกรม JSON ได้โดยไม่มีตัวเข้ารหัสที่กำหนดเอง (คีย์เป็นสิ่งที่ดึงดูด - ไม่ใช่ตัวเลือกของฉันเป็นเพียงปัญหาของฉัน)
Kasapo

1
สิ่งที่ดี. การใช้ความเข้าใจในพจนานุกรมจะรวบรัดถ้าลึกเพียงสองชั้น (เช่นdefaultdict(lambda: defaultdict(int))): {k: dict(v) for k, v in foo.items()}
ggorlen
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.