簡體   English   中英

python collections.defaultdict分配但不查找

[英]python collections.defaultdict on assignment but not on lookup

我有以下代碼:

from collections import *
nested_dict = lambda: defaultdict(nested_dict)
data = nested_dict()

這使我能夠將字典中的任何新“路徑”寫成一行:

data['A']['B']['C']=3

這就是我想要的。 但是我想在運行時得到一個異常(對於任何不存在的路徑):

var = data['A']['XXX']['C']

我覺得我在寫作時需要defaultdict,在閱讀時需要朴素的字典...

或者,是否有一種簡單的好方法來檢查defaultdict中是否存在``路徑''而不修改其內容...

我嘗試在查詢之前將defaultdict轉換回dict,希望:

dict(data)['A']['XXX']['C']

會引發異常...但是它一直在創建丟失的鍵...

一個明顯的解決方案是僅將簡單的dict與可以“具體化”中間鍵的函數一起使用:

def write_path(d, path, value):
    for key in path[:-1]:
        d = d.setdefault(key, {})
    d[path[-1]] = value

d = {}

write_path(d, ['a', 'b', 'c'], 3)
print(d)
print(d['a']['b']['c'])
print(d['a']['b']['d'])

輸出

{'a': {'b': {'c': 3}}}
3
Traceback (most recent call last):
  File "writedefaultdict.py", line 11, in <module>
    print(d['a']['b']['d'])
KeyError: 'd'

您無法在查找和寫入之間區分開來,因為查找是在data['A']['B']['C'] = 3分配中創建中介結構的。 在分配給'C'鍵之前,Python首先執行索引操作data['A'] ,然后首先執行['B'] __getitem____setitem____missing__參與,使這項工作掛鈎沒有給予足夠的情況下訪問之間進行區分,然后導致了'C'分配只從“閱讀” 'XXX'在你的第二個例子。

您實際上只有3個選項:

  • 不要使用defaultdict 編寫時,請使用dict.setdefault() 顯式創建新的嵌套字典; 您可以根據需要鏈接這些調用:

     var = {} var.setdefault('A', {}).setdefault('B', {})['C'] = 3 

    或者您可以將遞歸行為包裝在幾個函數中

  • 創建defaultdict結構的遞歸副本,以在完成編寫后將其替換為dict結構:

     def dd_to_d(dd): r = {} stack = [(r, dd)] while stack: target, dd = stack.pop() for key, value in dd.items(): if isinstance(value, defaultdict): sub = {} stack.append((sub, value)) value = sub target[key] = value return r var = dd_to_d(var) 
  • 將所有default_factory屬性設置為None以禁用為丟失的鍵創建新值:

     def disable_dd(dd): stack = [dd] while stack: dd = stack.pop() dd.default_factory = None for key, value in dd.items(): if isinstance(value, defaultdict): stack.append(value) disable_dd(var) 

暫無
暫無

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

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