在 Michael Driscoll 阅读 Python 101 的同时,我得到了关于检查字典中是否存在密钥的解释。我在我的机器上检查了一个包含密钥'a'
到'z'
的字典,其中值是它们的顺序,以及一个测量检索密钥't'
的时间的函数(随机选择它)
这是我的功能:
def f(d, flag):
start_time = time.time()
if flag:
print("t" in d)
else:
print("t" in d.keys())
print("--- %s seconds ---" % (time.time() - start_time))
以下是结果:
>>> f(dict,True)
True
--- 0.03937530517578125 seconds ---
>>> f(dict,False)
True
--- 0.05114388465881348 seconds ---
但我仍然没有得到它。我认为key in dict.keys()
会导致迭代更小的集合,这将更快。在in
或keys()
的实施中是否存在导致此问题的特殊内容?
答案 0 :(得分:8)
使用dictionary.keys()
的速度较慢,因为它更多工作:
dictionary.keys
keys()
),要求将当前调用帧压入堆栈,然后弹出。这些都不需要,因为针对字典的包含测试和键上的字典视图测试完全相同的事情。直接在字典上进行的遏制测试不包括这些值,在两种情况下,您都在测试键。
来自dict()
object documentation:
key in d
如果 d 有一个键键,则返回True
,否则返回False
。
请注意,使用步行时间不是测试性能差异的好方法。使用timeit
module代替最佳性能计时器,禁用GC以消除偏斜源,并多次重复测试以最小化系统偏斜。
您可以通过单独测试上述其他步骤(将调用和对象创建合并为一个)来重现时差。默认情况下,timeit.timet()
重复测试100万次,并返回所花费的总时间:
>>> import timeit
>>> from string import ascii_lowercase
>>> d = {l: i for i, l in enumerate(ascii_lowercase)}
>>> 't' in d
True
>>> timeit.timeit('d.keys', globals={'d': d})
0.0439452639548108
>>> timeit.timeit('keys()', globals={'keys': d.keys})
0.06267352704890072
因此,只查看.keys
属性100万次已经需要44毫秒,而调用方法(没有属性查找)又增加了63毫秒。但是这两种方法都有一些查询全局名称的开销:
>>> timeit.timeit('d', globals={'d': d})
0.027833244064822793
因此可以预期两种方法之间会有107 - 28 = = 79ms(大致)差异。
事实上,使用't' in d
和't' in d.keys()
之间的时差差不多:
>>> timeit.timeit('"t" in d.keys()', globals={'d': d})
0.11647015693597496
>>> timeit.timeit('"t" in d', globals={'d': d})
0.0370339349610731
116 - 37是79毫秒,正如预测的那样。