繁体   English   中英

用try检索字典项目的速度……除了字典中的键?

[英]Speed of retrieving dictionary items with try…except vs. key in dict?

我经常需要检查一个键是否在字典中,如果不是,则执行其他操作。 在 python 中,有两种明确的方法可以做到这一点:

if key in dict_:
   value = dict_[key]
   do_something
else:
   do_something_else

或者

try:
    value = dict_[key]
except KeyError:
    do_something_else
else:
    do_something

其中哪一个更快/更可取? 它取决于字典的大小吗?

似乎这里可能有两个相互竞争的效果:1)必须两次搜索键,与 2)设置异常堆栈跟踪。

您可以使用timeit对三种不同的方法进行基准测试。 get1try...exceptget2使用内置的.getget3首先检查。

In [1]: def get1(d, k): 
......:     try: 
......:         return d[k] 
......:     except KeyError: 
......:         return None 

In [3]: def get2(d, k): 
......:     return d.get(k) 

In [4]: def get3(d, k): 
......:    if k in d: return d[k]  
......:    else: return None 

在一本小字典(100 个元素)上

In [8]: %timeit -n 100 [get1(little_d, e) for e in range(len(little_d))]                
18.8 µs ± 270 ns per loop (mean ± std. dev. of 7 runs, 100 loops each)

In [9]: %timeit -n 100 [get2(little_d, e) for e in range(len(little_d))]                
22.5 µs ± 352 ns per loop (mean ± std. dev. of 7 runs, 100 loops each)

In [10]: %timeit -n 100 [get3(little_d, e) for e in range(len(little_d))]               
19.3 µs ± 862 ns per loop (mean ± std. dev. of 7 runs, 100 loops each)

还有一个更大的(1M 个元素)

In [11]: %timeit -n 100 [get1(big_d, e) for e in range(len(little_d))]
19.4 µs ± 469 ns per loop (mean ± std. dev. of 7 runs, 100 loops each)

In [12]: %timeit -n 100 [get2(big_d, e) for e in range(len(little_d))]
21.8 µs ± 241 ns per loop (mean ± std. dev. of 7 runs, 100 loops each)

In [13]: %timeit -n 100 [get3(big_d, e) for e in range(len(little_d))]
19.2 µs ± 128 ns per loop (mean ± std. dev. of 7 runs, 100 loops each)

在具有约 50%“未命中”( random.choices(range(0, 2*len(big_id)), k=len(big_d)) )的 (1M) 字典上显示更多差异:

In [20]: %timeit -n 100 [get1(big_d, e) for e in choices]                              
514 ms ± 10.4 ms per loop (mean ± std. dev. of 7 runs, 100 loops each)

In [21]: %timeit -n 100 [get2(big_d, e) for e in choices]                              
416 ms ± 4.54 ms per loop (mean ± std. dev. of 7 runs, 100 loops each)

In [22]: %timeit -n 100 [get3(big_d, e) for e in choices]                              
367 ms ± 4.89 ms per loop (mean ± std. dev. of 7 runs, 100 loops each)

在这种情况下, .get仍然会更快。

In [23]: %timeit -n 100 [big_id.get(e) for e in choices]                                
334 ms ± 3.6 ms per loop (mean ± std. dev. of 7 runs, 100 loops each)

它们看起来很接近,同样受字典大小的影响,但受未命中的影响不同。 唯一真正的影响大小将是 python 开始颠簸(可能?在这里)。 一个重要的注意事项是get2更慢,因为两个 function 调用( get2.get )的诱导开销在 python 中是昂贵的(如上一个测试所示)。 正如@user2864740指出的那样,由于各种原因,未命中将导致结果变慢。

tl;博士

我会使用.get


答案还很大程度上取决于密钥的__hash____eq__实现的速度。 如果__hash____eq__很慢,则对hash的两次调用的差异可能表明使方法 1 或 2(没有额外功能)更好。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM