在我的一个类中,我有许多方法都从相同的字典中绘制值。但是,如果其中一个方法试图访问不存在的值,则必须调用另一个方法来使该值与该键相关联。
我目前实现如下,其中findCrackDepth(tonnage)为self.lowCrackDepth [tonnage]赋值。
if tonnage not in self.lowCrackDepth:
self.findCrackDepth(tonnage)
lcrack = self.lowCrackDepth[tonnage]
但是,我也可以这样做
try:
lcrack = self.lowCrackDepth[tonnage]
except KeyError:
self.findCrackDepth(tonnage)
lcrack = self.lowCrackDepth[tonnage]
我假设两者之间存在性能差异,这与表中词的频率有关。这个差异有多大?我正在生成几百万个这样的值(在该类的许多实例中分布在许多字典中),并且每次该值都不存在时,可能会有两次这样的值。
答案 0 :(得分:14)
这是一个微妙的问题,因为你需要注意避免“持久的副作用”,性能权衡取决于缺失键的百分比。因此,请考虑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中实现的码)。
答案 1 :(得分:3)
检查密钥是否存在更便宜或至少与检索密钥一样便宜。因此,如果不在解决方案中,请使用,它更清晰,更易读。
根据你的问题,一个不存在的密钥不是一个类似错误的情况,因此没有充分的理由让python引发异常(即使你立即捕获它),如果你有一个,如果没有/ em>检查,每个人都知道你的意图 - 获得现有价值或以其他方式生成它。
答案 2 :(得分:2)
如有疑问,请参阅。
运行测试以查看在您的环境中,运行速度是否比另一个运行得快。
答案 3 :(得分:1)
如果是例外,请使用例外。如果您希望密钥在那里,请使用try / except,如果您不知道密钥是否在那里,请使用not in
。
答案 4 :(得分:0)
我相信dict的.get()
方法有一个用于设置默认值的参数。您可以使用它并将其放在一行中。我不确定它会如何影响性能。