2012-05-28 35 views
4

至少有兩個體面的嵌套字典實現我曾經遇到過,一個是to use defaultdict,另一個是to subclass dict沒有任何副作用嵌套字典實現

這兩種方法都工作得很好大部分的功能,不同的是訪問一個不存在的鍵值對時,他們都有一個副作用:它爲關鍵,存儲了與返回它創建了一個空字典

理想情況下,我希望在嘗試訪問不存在的密鑰時返回None而不創建條目(例如空字典)的實現。這是可行的嗎?

p.s.我知道我們可以通過使用元組作爲鍵來避免嵌套字典,但是這種實現並不適用於我,因爲我需要訪問嵌套字典的每個級別的條目集合。

+1

'get'方法適合您的需要嗎? d.get(key,None)用於字典'd'? – beardc

+0

需要支持哪個版本的Python? – Barry

+0

@Barry,我正在使用2.7 – skyork

回答

2

你必須放棄你返回無的要求。如果d[key] is None,d[key][subkey] = value相當於None[subkey] = value,這是行不通的。

你可以用缺失值做什麼,就是返回一個空的類似於字典的對象,而不必將它分配給一個鍵。如果該對象持有對父級的引用,則可以延遲該分配,直到在層級下有明確的分配。

示例實現(這是不完整的,你必須做的比覆蓋setitem有一個全功能的字典子類):

class NestedDict(dict): 
    def __init__(self, parent=None, parentkey=None): 
     self.parent = parent 
     self.parentkey = parentkey 

    def __missing__(self, key): 
     return NestedDict(self, key) 

    def __setitem__(self, key, value): 
     if self.parent is not None: 
      self.parent[self.parentkey] = self 
      self.parent = None 
     super(NestedDict, self).__setitem__(key, value) 

>>> d = NestedDict() 
>>> d[1][2][3] = 4 
>>> d[2] 
{} 
>>> d.keys() 
[1] 
>>> d[1][2][3] 
4 

另一種方法是將覆蓋__getitem____setitem__做當鍵是一個元組時,嵌套查找。此版本爲__getitem__提供了一個KeyError,以便與常規詞典保持一致。如果您願意,您可以輕鬆更改它以返回None。

class NestedDict(dict): 
    def __getitem__(self, key): 
     if isinstance(key, tuple): 
      try: 
       x = self 
       for k in key: 
        x = x[k] 
       return x 
      except (KeyError, TypeError): 
       raise KeyError(key) 
     else: 
      return super(NestedDict, self).__getitem__(key) 

    def __setitem__(self, key, value): 
     if isinstance(key, tuple): 
      d = self 
      for k in key[:-1]: 
       d = d.setdefault(k, NestedDict()) 
      d[key[-1]] = value 
     else: 
      super(NestedDict, self).__setitem__(key, value) 

>>> d = NestedDict() 
>>> d[1,2,3] = 4 
>>> d[1,2,3] 
4 
>>> d[1,2,4] 
KeyError: (1, 2, 4) 
>>> d 
{1: {2: {3: 4}}} 
2

東西兩個實現你點做了正常dict s是訪問一個不存在的鍵時返回一個dict。你想再次恢復這些,因而再次離開你默認dict類型:

>>> example = {} 
>>> example['foo'] 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
KeyError: 'foo' 
>>> example['foo'] = {} 
>>> example['foo']['bar'] = 1 

如果你想返回,而不是一個字典沒有,就用defaultdict(lambda: None)代替:

>>> from collections import defaultdict 
>>> example = defaultdict(lambda: None) 
>>> example['foo'] is None 
True 

注意你不能兩面都有; Python的首先必須找到第一個關鍵和解決的dict它可以看一下第二個鍵之前:如果您想d[key][subkey] = value與丟失的鑰匙工作

>>> example['foo']['bar'] 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
TypeError: 'NoneType' object is unsubscriptable 
1

Python支持duck typing針對這種情況:

>>> d={} 
>>> d[1]='Some' 
>>> try: 
... att=d[1] 
... except KeyError: 
... att=None 
... 
>>> print att 
Some 
>>> try: 
... att=d[1][2][3] 
... except KeyError: 
... att=None 
... 
>>> print att 
None 

捲到這一個類或函數,它應該很容易支持什麼,我認爲你正在尋找。