宽容的字典

时间:2010-07-29 00:19:33

标签: python dictionary defaultdict dictionary-missing

我想知道如何创建宽容字典(如果引发KeyError则返回默认值)。

在下面的代码示例中,我会得到一个KeyError;例如

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

为了不得到一个我将1.必须捕获异常或使用get。

我不想用我的字典做那个......

5 个答案:

答案 0 :(得分:22)

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

根据需要发出3。您也可以自己子类dict并覆盖__missing__,但是当defaultdict行为(忽略正在查找的确切缺失键)非常适合您时,这没有多大意义。 ..

修改 ... 除非,也就是说,每次查找丢失的密钥时,您都担心a会增加一个条目(是defaultdict语义的一部分),宁可放慢行为但要节省一些内存。例如,就记忆而言......:

>>> 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__以避免这种情况另外)每次支付“缺少密钥查找开销”。

当然,您是否关心任何问题(性能与内存占用量)完全取决于您的具体用例。在任何情况下 都是了解权衡的好主意! - )

答案 1 :(得分:7)

  

2.5版中的新功能:如果是。的子类   dict定义了一个方法__missing __(),   如果密钥不存在,则   d [key]操作调用该方法   用键键作为参数。该   d [键]操作然后返回或   提出任何返回或提出的东西   通过__missing __(键)调用如果   钥匙不存在。没有其他   操作或方法调用   __失踪__()。如果未定义__missing __(),则引发KeyError。   __missing __()必须是一个方法;它不能是实例变量。为   例如,请参阅collections.defaultdict。

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

答案 2 :(得分:5)

以下是如NullUserException

所建议的子类dict的方法
>>> 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}

如果你期待很多失误,这是非常重要的

答案 3 :(得分:3)

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

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

传递给构造函数的函数告诉类要返回什么作为默认值。有关其他示例,请参阅the documentation

答案 4 :(得分:0)

有时你真正想要的是.setdefault()这不是很直观,但它是一种“返回指定键的方法,如果它不存在,则将该键设置为该值”。

以下是使用setdefault()效果良好的示例:

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

这将允许我们创建一个字典,如:{'key1':[elem1, elem3], 'key2':[elem3]},而不必进行丑陋的检查以查看是否已存在密钥并为其创建列表。