宽容的字典

Jam*_*mes 9 python dictionary defaultdict dictionary-missing

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

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

a = {'one':1,'two':2}
print a['three']
Run Code Online (Sandbox Code Playgroud)

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

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

Ale*_*lli 22

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

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
Run Code Online (Sandbox Code Playgroud)

... 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
Run Code Online (Sandbox Code Playgroud)

......如你所见,完全可以节省内存开销.当然,性能是另一个问题:

$ 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
Run Code Online (Sandbox Code Playgroud)

由于defaultdict在查找时添加了(先前丢失的)密钥,因此在下次查找这样的密钥时会更快,而mydict(__missing__每次覆盖以避免添加)会支付"缺少密钥查找开销".

当然,您是否关心任何问题(性能与内存占用量)完全取决于您的具体用例.无论如何,要注意权衡这一点是个好主意! - )

  • 警告:只要defaultdict返回给定键的默认值,它就会向其自身插入一个新项.这将读取操作转变为潜在的写入操作,并且意味着查找大量丢失的密钥将导致其快速增长.http://docs.python.org/library/collections.html#collections.defaultdict.__missing__ (3认同)

Nul*_*ion 7

版本2.5中的新增内容:如果dict的子类定义方法__missing __(),则如果不存在键键,则d [key]操作将使用键键作为参数调用该方法.然后,如果密钥不存在,则d [key]操作返回或引发__missing __(key)调用返回或引发的任何内容.没有其他操作或方法调用__missing __().如果未定义__missing __(),则引发KeyError.__missing __()必须是一个方法; 它不能是实例变量.有关示例,请参阅collections.defaultdict.

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


Joh*_*ooy 5

以下是dictNullUserException建议的子类化方法

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

这个答案和Alex之间的一个很大区别是缺少的密钥没有添加到字典中

>>> print a
{'two': 2, 'one': 1}
Run Code Online (Sandbox Code Playgroud)

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