这是一个微妙的问题,因为您需要注意避免“持久的副作用”,并且性能折衷取决于丢失键的百分比。因此,请考虑以下dil.py
文件:
def make(percentmissing):
global d
d = dict.fromkeys(range(100-percentmissing), 1)
def addit(d, k):
d[k] = k
def with_in():
dc = d.copy()
for k in range(100):
if k not in dc:
addit(dc, k)
lc = dc[k]
def with_ex():
dc = d.copy()
for k in range(100):
try: lc = dc[k]
except KeyError:
addit(dc, k)
lc = dc[k]
def with_ge():
dc = d.copy()
for k in range(100):
lc = dc.get(k)
if lc is None:
addit(dc, k)
lc = dc[k]
以及一系列timeit
呼叫,例如:
$ python -mtimeit -s'import dil; dil.make(10)' 'dil.with_in()'
10000 loops, best of 3: 28 usec per loop
$ python -mtimeit -s'import dil; dil.make(10)' 'dil.with_ex()'
10000 loops, best of 3: 41.7 usec per loop
$ python -mtimeit -s'import dil; dil.make(10)' 'dil.with_ge()'
10000 loops, best of 3: 46.6 usec per loop
这表明,缺少10%的密钥,in
检查实际上是最快的方法。
$ python -mtimeit -s'import dil; dil.make(1)' 'dil.with_in()'
10000 loops, best of 3: 24.6 usec per loop
$ python -mtimeit -s'import dil; dil.make(1)' 'dil.with_ex()'
10000 loops, best of 3: 23.4 usec per loop
$ python -mtimeit -s'import dil; dil.make(1)' 'dil.with_ge()'
10000 loops, best of 3: 42.7 usec per loop
仅丢失1%的密钥,该exception
方法 略 快(get
无论哪种情况,该方法仍然是最慢的一种)。
因此,为了获得最佳性能,除非 (99%以上)的查找成功,否则该in
方法是可取的。
当然,还有另一种优雅的可能性:添加像…这样的dict子类:
class dd(dict):
def __init__(self, *a, **k):
dict.__init__(self, *a, **k)
def __missing__(self, k):
addit(self, k)
return self[k]
def with_dd():
dc = dd(d)
for k in range(100):
lc = dc[k]
然而…:
$ python -mtimeit -s'import dil; dil.make(1)' 'dil.with_dd()'
10000 loops, best of 3: 46.1 usec per loop
$ python -mtimeit -s'import dil; dil.make(10)' 'dil.with_dd()'
10000 loops, best of 3: 55 usec per loop
…虽然确实很漂亮,但这并不是性能上的赢家- 即便采用这种get
方法,或更慢的速度,也要使用外观漂亮的代码来实现。(在defaultdict
语义上类似于此类dd
,如果适用的话,将是性能上的胜利,但这是因为__missing__
在这种情况下,特殊方法是在经过优化的C代码中实现的)。