Python:try except KeyError 与 if has_key()

19
在下面的代码中,哪种方法更高效/更符合Python风格?使用 try-catch 子句还是 if-else 子句?
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.

:这是一个常见的缩写,表示“对比”或“对抗”。
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

我倾向于使用try catch选项,但我不确定为什么。


在我看来,第二种方式更加易于理解。而且,使用try-catch会增加额外的开销。 - Seçkin Savaşçı
请参见https://dev59.com/DmjWa4cB1Zd3GeqPoj_-,其中介绍了如何计算文本文件中字母的频率。 - Ashwini Chaudhary
没有人提到可以通过“in”进行成员资格测试。在我看来,“if c in letters:”更加清晰易读。 - meawoppl
4个回答

23

使用dict.get():

get(key[, default])

如果字典中存在key,则返回对应的值,否则返回default。如果未指定default,则默认为None,因此该方法永远不会引发KeyError

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

示例:

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}

@zenpoy 正在尝试计算文本中的字母,而你的答案没有进行任何计算! - FallenAngel
1
letters[c] = letters.get(c,1) - piokuc
3
@piokuc 所说的 letters[c] = letters.get(c,0) + 1 更好一些。 - zenpoy
是的,抱歉,我只是想说Ashwin的回答还不错。 - piokuc
1
@zenpoy 来自 help(dict.get) --> get(...) D.get(k[,d]) -> D[k] if k in D, else d。其中 d 默认为 None。这是一个简单的三元运算符。 - Ashwini Chaudhary
显示剩余3条评论

17

根据您的Python版本,您可能希望在此处使用defaultdictCounter,因为它们是最适合的。

现在,关于哪种替代方案是最pythonic的,这取决于您要问的人。一方面,基于异常的流程控制有时会被看作是不好的做法,因为异常应该在异常情况下触发,而不应该用作条件语句。

另一方面,在某些情况下,你会更愿意使用try / except,因为条件语句并不实用。

最后,从性能角度来看,它取决于您是否希望大部分时间都存在键(if语句稍微慢一点,但是当引发异常时,异常比if语句要慢得多),如果性能是一个问题,则应在决定之前使用两种实现方式进行性能测量。


总的来说,我认为一个经验法则是默认使用条件语句,但在实际情况下更实用/更有意义/真正需要加速时,使用异常处理。


10

更符合 Python 风格的方法是使用专门的工具:

from collections import Counter

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

请注意,has_key已经被弃用,推荐使用in


1

看看你能否使用这个技巧来优雅地处理异常。

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

参考资料:https://wiki.python.org/moin/KeyError


这是Aशwini चhaudhary的回答... - zenpoy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接