2012-02-16 47 views
13

我期待在python中創建一個簡單的「查找」機制,並希望確保沒有什麼東西隱藏在python的龐大的圖書館中,尚未做到這在創建之前。訪問python字典與多個鍵查找字符串

我期待採取格式化像這樣

my_dict = { 
    "root": { 
    "secondary": { 
     "user1": { 
      "name": "jim", 
      "age": 24 
     }, 
     "user2": { 
     "name": "fred", 
     "age": 25 
     } 
    } 
    } 
} 

的字典,我想有辦法通過使用十進制表示,這將是類似的東西,以

訪問數據
root.secondary.user2 

並將返回結果字典作爲迴應。我在想,一定有這樣做,我可以寫一個沒有太大困難,但我想確保我沒有重新創建我可能從文檔中丟失的東西。由於

+0

你在尋找語法糖('mydict.root.secondary.user2')還是隻通過字符串查找? – 2012-02-16 23:40:44

回答

28

沒什麼用於此目的的標準庫,但比較容易將此代碼自己:

>>> key = "root.secondary.user2" 
>>> reduce(dict.get, key.split("."), my_dict) 
{'age': 25, 'name': 'fred'} 

這利用的事實,查找在關鍵k字典d可以寫成dict.get(d, k)。反覆應用reduce()可以產生所需的結果。

編輯:爲完整三種功能獲取,設置或使用這種方法刪除字典鍵:

def get_key(my_dict, key): 
    return reduce(dict.get, key.split("."), my_dict) 

def set_key(my_dict, key, value): 
    key = key.split(".") 
    my_dict = reduce(dict.get, key[:-1], my_dict) 
    my_dict[key[-1]] = value 

def del_key(my_dict, key): 
    key = key.split(".") 
    my_dict = reduce(dict.get, key[:-1], my_dict) 
    del my_dict[key[-1]] 
+0

這適用於檢索,但關於實際更新該字典中的字段的任何想法使用相同的方法 – Tanerax 2012-02-16 23:20:34

+0

+1作爲reduce()的答案;儘管我也很簡單,就像答案一樣,希望我能+2。 – SingleNegationElimination 2012-02-16 23:39:22

+0

@Tanerax:要進行更新,請拆分密鑰的最後一個組件,並使用主要組件檢索包含的字典。爲答案添加了示例代碼。 – 2012-02-16 23:41:37

1

遞歸仍然有效。

def walk_into(dict, key): 
    head, _, tail = key.partition('.') 
    if tail: 
     return walk_into(dict[head], tail) 
    return dict, key 
d, k = walk_into(my_dict, "root.secondary.user2") 

d[k]可用於獲取或投入新的價值。

2

你可以有。您可以通過使用類似於下面的代碼來繼承字典,添加密鑰查找(甚至保留名稱字典)。然而,{...}表單仍將使用內置的dict類(現在稱爲orig_dict),因此您必須將其括起來,如下所示:Dict({...})。這個實現遞歸地將字典轉換爲新的形式,所以你不必使用上面的方法來處理任何普通字典本身的字典條目。

orig_dict = dict 
class Dict(orig_dict): 
    def __init__(self, *args, **kwargs): 
     super(Dict, self).__init__(*args, **kwargs) 
     for k, v in self.iteritems(): 
      if type(v) == orig_dict and not isinstance(v, Dict): 
       super(Dict, self).__setitem__(k, Dict(v)) 
    def __getattribute__(self, k): 
     try: return super(Dict, self).__getattribute__(k) 
     except: return self.__getitem__(k) 
    def __setattr__(self, k, v): 
     if self.has_key(k): self.__setitem__(k, v) 
     else: return super(Dict, self).__setattr__(k, v) 
    def __delattr__(self, k): 
     try: self.__delitem__(k) 
     except: super(Dict, self).__delattr__(k) 
    def __setitem__(self, k, v): 
     toconvert = type(v) == orig_dict and not isinstance(v, Dict) 
     super(Dict, self).__setitem__(k, Dict(v) if toconvert else v) 

# dict = Dict <-- you can even do this but I advise against it 

# testing: 
b = Dict(a=1, b=Dict(c=2, d=3)) 
c = Dict({'a': 1, 'b': {'c': 2, 'd': 3}}) 
d = Dict(a=1, b={'c': 2, 'd': {'e': 3, 'f': {'g': 4}}}) 

b.a = b.b 
b.b = 1 
d.b.d.f.g = 40 
del d.b.d.e 
d.b.c += d.b.d.f.g 
c.b.c += c.a 
del c.a 
print b 
print c 
print d