2010-07-29 49 views
9

我想知道如何創建寬容的字典(如果引發KeyError返回一個默認值)。一個寬容的字典

在下面的代碼示例中,我會得到一個KeyError;例如

a = {'one':1,'two':2} 
print a['three'] 

爲了不獲得一個我會1.必須趕上例外或使用得到。

我想不會有這樣做與我的字典...

+2

'collections.defaultdict'是您的電池供電解決方案。 – 2010-07-29 00:40:47

+1

問題標題爲+1 – 2010-07-29 01:02:52

回答

22
import collections 
a = collections.defaultdict(lambda: 3) 
a.update({'one':1,'two':2}) 
print a['three'] 

發出3的要求。你也可以繼承dict自己和覆蓋__missing__,但這並沒有多大意義,當defaultdict行爲(忽略就是BEING擡頭確切缺少鍵)適合你這麼好......

編輯 ... 除非,也就是說,每次查找缺少的鍵(這是defaultdict的語義的一部分)時,您擔心a會增長一個條目,並且寧願獲得較慢的行爲但保存一些內存。例如,在內存方面...:

>>> import sys 
>>> a = collections.defaultdict(lambda: 'blah') 
>>> print len(a), sys.getsizeof(a) 
0 140 
>>> for i in xrange(99): _ = a[i] 
... 
>>> print len(a), sys.getsizeof(a) 
99 6284 

...的defaultdict,原本空的,現在有,我們查閱了99先前丟失的鑰匙,並採取6284個字節(相對於140個字節當它是空的時候)。

另一種方法...:

>>> class mydict(dict): 
... def __missing__(self, key): return 3 
... 
>>> a = mydict() 
>>> print len(a), sys.getsizeof(a) 
0 140 
>>> for i in xrange(99): _ = a[i] 
... 
>>> print len(a), sys.getsizeof(a) 
0 140 

...完全當你看到這節省了內存開銷。當然,性能是另一個問題:

$ python -mtimeit -s'import collections; a=collections.defaultdict(int); r=xrange(99)' 'for i in r: _=a[i]' 
100000 loops, best of 3: 14.9 usec per loop 

$ python -mtimeit -s'class mydict(dict): 
> def __missing__(self, key): return 0 
> ' -s'a=mydict(); r=xrange(99)' 'for i in r: _=a[i]' 
10000 loops, best of 3: 92.9 usec per loop 

由於defaultdict增加上查找(以前缺失)鍵,它會更快,當這樣的關鍵是下一個擡頭,而mydict(它覆蓋__missing__避免另外)每次支付「缺少密鑰查找開銷」。

無論你關心任何問題(性能與內存佔用)完全取決於你的具體使用情況,當然。它是在任何情況下要注意權衡的一個好主意 - )

+3

警告:defaultdict只要返回給定密鑰的默認值,就會在其中插入一個新項目。這會將讀取操作轉化爲潛在的寫入操作,並且意味着查找大量丟失的鍵會使其快速增長。 http://docs.python.org/library/collections.html#collections.defaultdict.__missing__ – 2010-07-29 01:25:57

+0

@Forest,好點!讓我相應地編輯。 – 2010-07-29 01:30:57

+0

優秀的職位!你的倒數第二段似乎與你的例子無關,因爲你從不使用同一個鍵兩次。所以,即使你不重複一個密鑰,defaultdict似乎更快,如果你這樣做,速度更快。是對的嗎? – 2010-07-29 13:50:53

7

新版本2.5:如果 字典的一個子類定義的方法__missing __(), 如果鍵鍵不目前, d [鍵]操作將鍵鍵作爲參數調用方法 。如果 密鑰不存在,則返回 d [key]操作或返回 引發__missing __(key)調用返回或引發 的任何操作。操作或方法沒有其他 __missing __()。如果__missing __()未定義,則引發KeyError。 __missing __()必須是一個方法;它不能是一個實例變量。有關 示例,請參閱collections.defaultdict。

http://docs.python.org/library/stdtypes.html

3

你可能想使用defaultdict(它需要ATLEAST的python2.5我相信)

from collections import defaultdict 
def default(): return 'Default Value' 
d = defaultdict(default) 
print(d['?']) 

傳遞給構造函數告訴類什麼作爲默認值返回。有關其他示例,請參見the documentation

5

這裏是如何繼承dict由NullUserException的建議

>>> class forgiving_dict(dict): 
...  def __missing__(self, key): 
...   return 3 
... 
>>> a = forgiving_dict() 
>>> a.update({'one':1,'two':2}) 
>>> print a['three'] 
3 

這個答案和Alex的之間的一個很大的區別在於缺少的關鍵是添加到字典

>>> print a 
{'two': 2, 'one': 1} 

哪如果你期望有很多的遺漏,這是相當重要的

0

有時候你會盟友想要的是.setdefault()這不是很直觀,但它是一種「返回指定的密鑰,如果它不存在,將該密鑰設置爲此值」的方法。

這裏是正在使用,效果良好的setdefault()一個例子:

collection = {} 
for elem in mylist: 
    key = key_from_elem(elem) 
    collection.setdefault(key, []).append(elem) 

這將使我們能夠創建這樣一個字典:{'key1':[elem1, elem3], 'key2':[elem3]}無須擁有一個醜陋的檢查,看是否有一個鍵已經存在和爲它創建一個列表。