起步

从字典中取值有两个方法,一个是先判断key是否在字典中再取值;另一个是包裹try块中直接去取值:

def use_in(d, key):
    if key in d:
        return d[key]
    return None

def use_try(d, key):
    try:
        return d[key]
    except KeyError:
        pass
    return None

性能比较

timeit 模块来查看它们的运行时间,测试环境 win10 + python3.6.8:

import timeit

def use_in(d, key):
    if key in d:
        return d[key]
    return None

def use_try(d, key):
    try:
        return d[key]
    except KeyError:
        pass
    return None

cache = {}
for i in range(100):
    cache[i] = True

perf_dict = {
    'in: hit': min(timeit.repeat(lambda: use_in(cache, 50))),
    'in:not hit': min(timeit.repeat(lambda: use_in(cache, 150))),
    'try: hit': min(timeit.repeat(lambda: use_try(cache, 50))),
    'try:not hit': min(timeit.repeat(lambda: use_try(cache, 150))),
}

print(perf_dict)

得到结果:

{
    'in: hit': 0.32121160000000004, 
    'in:not hit': 0.2666487000000002, 
    'try: hit': 0.27908409999999995, 
    'try:not hit': 0.5742989999999999
}

好像用 try 的方式的快一些,但当不命中的时候几乎慢了一倍多。所以平均下来这两个方法性能其实没啥区别。

标准库里会用哪种方法呢

比较好奇标准库中会用哪种方法呢?

in先判断的方式

argparse 模块中:

20190802105237.png

linecache 模块:

20190802105523.png

dummy_threading 模块:

20190802111704.png

try块的方式

re 模块中的 _compile 中:

20190802104313.png

string 模块中:

20190802104455.png

datetime 模块中:

20190802104609.png

functools 模块中:

20190802104735.png

copy 模块:

20190802111944.png

threading 模块:

20190802112125.png

更多的就不举例了,可以看到,在标准库里大多还是使用 try 块的方式。然后是一些不常用或者比较“新”的模块才用 in 判断方式。可能是早先前的字典不支持 in 操作吧。

总结

就我个人而言,我会更倾向于使用 in 先判断的方式。因为这方方式能少去处理异常。毕竟一个 try 块都要为它申请新的堆栈空间的。


本文由 hongweipeng 创作,采用 署名-非商业性使用-相同方式共享 3.0,可自由转载、引用,但需署名作者且注明文章出处。

如果对您有用,您的支持将鼓励我继续创作!