是先尝试并捕获异常好还是先测试是否可能以避免异常好?
我应该先检查一下某个东西是否有效,还是直接尝试去做,然后捕捉可能出现的错误呢?
- 有没有什么可靠的文档说明哪种方式更好?
- 哪种方式更符合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 个回答
如果有可能出现竞争条件,使用 try
和 except
直接处理错误,而不是放在 if
语句里,应该始终这样做。比如说,如果你想确保一个文件夹存在,不要这样做:
import os, sys
if not os.path.isdir('foo'):
try:
os.mkdir('foo')
except OSError, e
print e
sys.exit(1)
因为如果在 isdir
和 mkdir
之间,有其他线程或进程创建了这个文件夹,你的程序就会直接退出。正确的做法是这样:
import os, sys, errno
try:
os.mkdir('foo')
except OSError, e
if e.errno != errno.EEXIST:
print e
sys.exit(1)
这样的话,只有在无法创建 'foo' 文件夹时,程序才会退出。
在这个特定的情况下,你应该完全使用其他的方法:
x = myDict.get("ABC", "NO_ABC")
不过一般来说:如果你觉得测试会经常失败,就用 if
。如果测试的成本比较高,也就是说比直接尝试操作然后捕捉错误要贵,就用 try
。如果这两种情况都不适用,那就选择看起来更简单易懂的方式。
如果能让代码运行得更快或者让代码看起来更简洁,建议使用 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