为什么Dictionary.keys()中的键比字典中的键慢? [英] how come key in dictionary.keys() slower than key in dictionary?

查看:121
本文介绍了为什么Dictionary.keys()中的键比字典中的键慢?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在阅读 Michael Driscoll Python 101 时,我得到了他对检查字典中是否存在键的解释.我在计算机上用字典进行了检查,该字典包含键'a''z'(其值为顺序),以及一个用于测量检索键't'的时间的函数(随机选择)

While reading Python 101 by Michael Driscoll I got to his explanation on checking if a key exists in a dictionary. I checked it on my machine with a dictionary containing keys 'a' to 'z' where the value is their order, and a function that measures time on retrieving the key 't' (picked it at random)

这是我的职能:

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()会导致在更小的集合上进行迭代,这会更快. inkeys()的实现中是否有某些特殊原因导致这种情况?

BUT, I still don't get it. I thought that key in dict.keys() would result in iteration on much smaller collection, which will be faster. Is there something special in the implementation of in or keys() that causes this?

推荐答案

使用dictionary.keys()速度较慢,因为它可以完成更多工作:

Using dictionary.keys() is slower because it does more work:

  • 它添加了一个属性查找; dictionary.keys
  • 它添加了一个方法调用(keys()),要求将当前调用框架推入堆栈,然后弹出.
  • 必须为返回值创建另一个对象(字典视图).这是一个轻量级的对象,但是您仍然需要在堆上为其分配内存.
  • It adds an attribute lookup; dictionary.keys
  • It adds a method call (keys()), requiring the current call frame to be pushed onto the stack, and popped afterwards.
  • Another object has to be created for the return value (a dictionary view). It's a light-weight object, but you still need to allocate memory for it on the heap.

这些都不是必需的,因为针对字典的包含测试和键上的字典视图测试了完全相同的事物.在这两种情况下,直接在字典上进行的包含测试均不包含这些值,您仅在测试键 .

None of this is needed, because a containment test against the dictionary and the dictionary view on the keys test the exact same thing. Containment testing directly on a dictionary does not include the values, you are testing for keys only, in both cases.

dict()对象文档:

key in d
如果 d 具有键 key ,则返回True,否则返回False.

key in d
Return True if d has a key key, else False.

请注意,使用步行时间并不是测试性能差异的好方法.请使用 timeit模块,它会选择性能最佳的计时器,并禁用GC消除了歪斜的根源,并重复了多次测试以最大程度地减少系统歪斜.

Note that using walk-clock time is not a great way of testing for performance differences. Use the timeit module instead, which picks the best performing timer, disables the GC to eliminate a source of skew, and repeats the test many times to minimise system skew.

您可以通过分别测试上述其他步骤(将调用和对象创建合并为一个)来重现时间差.默认情况下,timeit.timet()重复测试一百万次,并返回所花费的总时间:

You can reproduce the time difference by testing for the additional steps above separately (combining the call and object creation into one). By default timeit.timet() repeats the test 1 million times and returns the total time taken:

>>> 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

因此,仅查找100万次.keys属性已经花费了44毫秒,而调用该方法(不进行属性查找)又增加了63ms.但这两种方法都有一些查找全局名称的开销:

So merely looking up the .keys attribute 1 million times already takes 44 milliseconds, while calling the method (without attribute lookup) adds another 63ms. Both methods have some overhead for looking up the global name however:

>>> timeit.timeit('d', globals={'d': d})
0.027833244064822793

因此,人们希望两种方法之间的差值为107-28 == 79ms(大约).

So one would expect there to be a 107 - 28 == 79ms (roughly) difference between the two methods.

实际上,使用't' in d't' in d.keys()的时间差大约是这样:

And indeed, the time difference between using 't' in d and 't' in d.keys() is about that much:

>>> timeit.timeit('"t" in d.keys()', globals={'d': d})
0.11647015693597496
>>> timeit.timeit('"t" in d', globals={'d': d})
0.0370339349610731

116-37是79毫秒,如预期的那样.

116 - 37 is 79 milliseconds, as predicted.

这篇关于为什么Dictionary.keys()中的键比字典中的键慢?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆