簡體   English   中英

如何將defaultdicts [defaultdicts]的defaultdict轉換為dicts [of dicts]的dict?

[英]How to convert defaultdict of defaultdicts [of defaultdicts] to dict of dicts [of dicts]?

使用這個答案 ,我創建了defaultdictdefaultdict 現在,我想把那個深層嵌套的dict對象變回普通的python dict。

from collections import defaultdict

factory = lambda: defaultdict(factory)
defdict = factory()
defdict['one']['two']['three']['four'] = 5

# defaultdict(<function <lambda> at 0x10886f0c8>, {
#             'one': defaultdict(<function <lambda> at 0x10886f0c8>, {
#                 'two': defaultdict(<function <lambda> at 0x10886f0c8>, {
#                     'three': defaultdict(<function <lambda> at 0x10886f0c8>, {
#                         'four': 5})})})})

我認為這不是正確的解決方案:

import json

regdict = json.loads(json.dumps(defdict))

# {u'one': {u'two': {u'three': {u'four': 5}}}}

此外, 這個答案是不充分的,因為它沒有遞歸嵌套的字典。

你可以在樹上遞歸,用dict理解產生的dict替換每個defaultdict實例:

def default_to_regular(d):
    if isinstance(d, defaultdict):
        d = {k: default_to_regular(v) for k, v in d.items()}
    return d

演示:

>>> from collections import defaultdict
>>> factory = lambda: defaultdict(factory)
>>> defdict = factory()
>>> defdict['one']['two']['three']['four'] = 5
>>> defdict
defaultdict(<function <lambda> at 0x103098ed8>, {'one': defaultdict(<function <lambda> at 0x103098ed8>, {'two': defaultdict(<function <lambda> at 0x103098ed8>, {'three': defaultdict(<function <lambda> at 0x103098ed8>, {'four': 5})})})})
>>> default_to_regular(defdict)
{'one': {'two': {'three': {'four': 5}}}}

實際上要做的是腌制你的遞歸defaultdict 並且你不關心你是否在defaultdict時回到了dictdefaultdict

雖然有很多方法可以解決這個問題(例如,使用自己的pickle創建一個defaultdict子類,或者使用copyreg顯式覆蓋默認的子類),但是有一種方法可以解決這個問題。

注意嘗試時得到的錯誤:

>>> pickle.dumps(defdict)
PicklingError: Can't pickle <function <lambda> at 0x10d7f4c80>: attribute lookup <lambda> on __main__ failed

你不能腌制lambda定義的函數,因為它們是匿名的,這意味着它們永遠不會被打開。

但實際上沒有理由這個函數需要由lambda定義。 特別是,您甚至不希望它是匿名的,因為您明確地給它起了一個名字。 所以:

def factory(): return defaultdict(factory)

而且你已經完成了。

這是在行動:

>>> from collections import defaultdict
>>> def factory(): return defaultdict(factory)
>>> defdict = factory()
>>> defdict['one']['two']['three']['four'] = 5
>>> import pickle
>>> pickle.dumps(defdict)
b'\x80\x03ccollections\ndefaultdict\nq\x00c__main__\nfactory\nq\x01\x85q\x02Rq\x03X\x03\x00\x00\x00oneq\x04h\x00h\x01\x85q\x05Rq\x06X\x03\x00\x00\x00twoq\x07h\x00h\x01\x85q\x08Rq\tX\x05\x00\x00\x00threeq\nh\x00h\x01\x85q\x0bRq\x0cX\x04\x00\x00\x00fourq\rK\x05ssss.'

在其他情況下,沒有正當理由使用lambda而不是def會導致問題 - 你無法在運行時反省你的函數,你在調試器中得到更糟的回溯等等。當你想要一個固有的匿名函數時使用lambda ,或者您可以在表達式中間定義的函數,但不要使用它來保存三個字符的輸入。

一種可能性是你可以創建自己的類,可以從“defaultdict”模式切換到“vanilla”模式。 對於大型詞典,這會更快,更快。 這是一個覆蓋getitem方法並具有適當的實例變量來控制行為的問題。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM