![](/img/trans.png)
[英]`if key in dict` vs. `try/except` - which is more readable idiom?
[英]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
对三种不同的方法进行基准测试。 get1
是try...except
, get2
使用内置的.get
, get3
首先检查。
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指出的那样,由于各种原因,未命中将导致结果变慢。
我会使用.get
。
答案还很大程度上取决于密钥的__hash__
和__eq__
实现的速度。 如果__hash__
和__eq__
很慢,则对hash
的两次调用的差异可能表明使方法 1 或 2(没有额外功能)更好。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.