是先尝试并捕获异常好还是先测试是否可能以避免异常好?

153 投票
8 回答
50748 浏览
提问于 2025-04-17 03:23

我应该先检查一下某个东西是否有效,还是直接尝试去做,然后捕捉可能出现的错误呢?

  • 有没有什么可靠的文档说明哪种方式更好?
  • 哪种方式更符合Python的风格?

举个例子,我应该:

if len(my_list) >= 4:
    x = my_list[3]
else:
    x = 'NO_ABC'

还是:

try:
    x = my_list[3]
except IndexError:
    x = 'NO_ABC'

一些想法...
PEP 20 说:

错误不应该悄悄溜走。
除非被明确地处理掉。

那么,使用 try 而不是 if 是不是可以理解为错误悄悄溜走了呢?如果是这样的话,使用这种方式是否就相当于明确地处理掉了错误,从而是可以接受的呢?


不是在说只能用一种方式的情况;比如:

try:
    import foo
except ImportError:
    import baz

8 个回答

10

如果有可能出现竞争条件,使用 tryexcept 直接处理错误,而不是放在 if 语句里,应该始终这样做。比如说,如果你想确保一个文件夹存在,不要这样做:

import os, sys
if not os.path.isdir('foo'):
  try:
    os.mkdir('foo')
  except OSError, e
    print e
    sys.exit(1)

因为如果在 isdirmkdir 之间,有其他线程或进程创建了这个文件夹,你的程序就会直接退出。正确的做法是这样:

import os, sys, errno
try:
  os.mkdir('foo')
except OSError, e
  if e.errno != errno.EEXIST:
    print e
    sys.exit(1)

这样的话,只有在无法创建 'foo' 文件夹时,程序才会退出。

22

在这个特定的情况下,你应该完全使用其他的方法:

x = myDict.get("ABC", "NO_ABC")

不过一般来说:如果你觉得测试会经常失败,就用 if。如果测试的成本比较高,也就是说比直接尝试操作然后捕捉错误要贵,就用 try。如果这两种情况都不适用,那就选择看起来更简单易懂的方式。

172

如果能让代码运行得更快或者让代码看起来更简洁,建议使用 try/except 而不是 if/else

  • 速度更快(比如可以避免多次查找)
  • 代码更简洁(行数更少,更容易阅读)

通常,这两者是相辅相成的。


速度更快

当你想在一个很长的列表中查找某个元素时:

try:
    x = my_list[index]
except IndexError:
    x = 'NO_ABC'

如果你觉得这个 index 很可能在列表里,并且通常不会出现索引错误,那么使用 try/except 是最好的选择。这样你就可以避免额外的查找,比如不需要再写 if index < len(my_list)

Python 鼓励使用异常,你需要处理它们,这是来自于 Dive Into Python 的一句话。你的例子不仅优雅地处理了异常,而不是让它 默默无视,而且异常只在 特殊 情况下发生,比如索引没有找到(所以叫做 异常!)。


更简洁的代码

官方的 Python 文档提到了一种编程风格 EAFP,意思是 请求原谅比请求许可更容易Rob Knight 指出,捕获错误而不是避免错误,可以让代码更简洁、更容易阅读。他的例子是这样说的:

更糟糕的方式 (LBYL '跳之前先看')

#check whether int conversion will raise an error
if not isinstance(s, str) or not s.isdigit():
    return None
elif len(s) > 10:    #too many digits for int conversion
    return None
else:
    return int(s)

更好的方式 (EAFP: 请求原谅比请求许可更容易)

try:
    return int(s)
except (TypeError, ValueError, OverflowError): #int conversion failed
    return None

撰写回答