关于性能:Python:尝试除KeyError vs如果has_key()

Python: try except KeyError vs if has_key()

本问题已经有最佳答案,请猛点这里访问。

在下面的代码中,什么更有效/更"Python"?使用try catch子句还是if else子句?

1
2
3
4
5
6
7
8
9
10
11
12
13
fname = 'AdobeARM.log'

letters = {}

with open(fname,'r') as f:
    for line in f:
        for c in line:
            try:
                letters[c] += 1
            except KeyError:
                letters[c] = 1

print letters

VS

1
2
3
4
5
6
7
8
9
10
11
12
13
fname = 'AdobeARM.log'

letters = {}

with open(fname,'r') as f:
    for line in f:
        for c in line:
            if letters.has_key(c):
                letters[c] += 1
            else:
                letters[c] = 1

print letters

我倾向于选择尝试捕捉,但我不知道为什么。


使用dict.get()

get(key[, default])

Return the value for key if key is in the dictionary, else default. If
default is not given, it defaults to None, so that this method never
raises a KeyError.

换句话说,d.get('x', c)相当于d['x'] if 'x' in d else c

例子:

1
2
3
4
5
6
7
8
9
10
11
In [24]: d = {'a':1, 'b':2}

In [27]: d['d'] = d.get('d', 0) + 1  # 0 is the default value

In [28]: d
Out[28]: {'a': 1, 'b': 2, 'd': 1}

In [29]: d['d'] = d.get('d', 0) + 1

In [30]: d
Out[30]: {'a': 1, 'b': 2, 'd': 2}


根据您的python版本,您可能希望在这里使用defaultdictCounter,因为这是最合适的。

现在,关于哪种选择最适合做Python,这取决于你要问的人。一方面,基于异常的流控制有时是不受欢迎的,因为异常应该在异常情况下提出,而不是用作条件。

但是,另一方面,在某些情况下,您更愿意使用try/except,因为条件不实际。

最后,从性能的角度来看,这取决于您是否希望您的密钥大部分时间都在那里(if语句有点慢,但异常在提出时慢得多),如果性能是一个问题,那么在决定之前,您应该使用两个实现来衡量您的性能。

总之,我认为一般的经验法则是默认情况下使用条件,但是如果条件更实用/更有意义/给你真正需要的加速,就使用例外。


更多的Python是使用专门的工具来完成这项工作:

1
2
3
4
from collections import Counter

with open(fname, 'r') as f:
    letters = Counter(f.read())

还要注意的是,has_key被否决,而倾向于in


看看你是否能用这个技巧来处理异常的皮托管。

1
2
3
4
adict = {}
default = None
val = adict.get('dogname', default)
# val will be None rather than raise an exception.

参考:https://wiki.python.org/moin/keyror