我在一些代码中有一个字典,它将一个键映射到一个单词,键是md5
哈希的结果。我的代码基本上希望获得key
的{{1}},当它不存在时,将其添加到字典中
这是我的第一个实现:
word
在分析我的代码后,我发现这非常慢。那么我试过这个,功能相同
key = int(hashlib.md5(word).hexdigest(), 16)
if key in self.id_to_word.keys():
assert word == self.id_to_word[key]
else:
self.id_to_word[key] = word
return key
结果令人难以置信的更快。虽然我对性能改进感到高兴,但我想知道是否有人可以向我解释原因。从类似的字典中检查key = int(hashlib.md5(word).hexdigest(), 16)
try:
assert word == self.id_to_word[key]
return key
except KeyError:
self.id_to_word[key] = word
函数中的某些东西是不好的做法吗?它每次都会产生副本(浪费大量的计算)吗?
答案 0 :(得分:3)
id_to_word.keys()
创建一个新的列表,该列表是线性搜索的,比散列查找慢得多。删除.keys()
。
最快的方法是:
key = int(hashlib.md5(word).hexdigest(), 16)
assert word == self.id_to_word.setdefault(key, word)
答案 1 :(得分:2)
这是预期的(在python2中)。 keys()
方法返回键的列表。因此,使用列表中的in
运算符需要线性时间。
尝试访问该项是恒定时间,这要快得多。
注意:您只需使用key in dictionary
代替try: ...except:
。
请注意,词典具有setdefault
方法,已经可以执行您想要的操作。此外,如果您在很长一段时间内执行该操作,则应考虑使用collections.defaultdict
而不是普通字典。
答案 2 :(得分:2)
key in some_dict
比key in some_dict.keys()
Dict Lookup key in some_dict
的复杂度为O(1)
因此非常快
表示,如果密钥在dict中,它仍然(非常轻微)慢于try/except
真正的答案是这两种方法之间没有真正可衡量的差异,并且做对你感觉不错的事情
答案 3 :(得分:1)
阐述我上面的评论:
In [4]: d = {k:k for k in xrange(1000)}
In [5]: %timeit 50 in d
10000000 loops, best of 3: 68.6 ns per loop
In [6]: %timeit 50 in d.keys()
100000 loops, best of 3: 6.35 µs per loop
如您所见,使用d.keys()的速度大约慢100倍。
答案 4 :(得分:0)
如上所述,setdefault()
解决了您的问题,但没有if
或try
阻止。
但是"更容易要求宽恕而不是许可" [EAFP]和鸭子打字是Python中常见的习惯用语,相比之下更具防御性的“先寻找你”#34; [LBYL]在其他语言中常见的习语,例如Java,C ++。
Jeff Knuth在其上发表了一篇有趣的博文Write Clean Python: Use Exceptions