优雅的处理Python的错误或是异常是构建稳定程序的重要组成部分。在一些应用中,很多函数只能处理特定的输入。例如,Python的float函数可以将字符串转化为浮点数,但是对不正确的输入会产生ValueError:
float('1.2345')
1.2345
float('something')
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-2-2649e4ade0e6> in <module>()
----> 1 float('something')
ValueError: could not convert string to float: 'something'
假设我们想要在float函数运行失败时可以优雅地返回输入参数。我们可以通过将float函数写入一个try/except代码段来实现:
def float_1(x):
try:
return float(x)
except:
return x
如果float(x)执行时抛出了异常,则代码段中的except部分代码将会被执行:
float_1('1.2345')
1.2345
float_1('something')
'something'
当然除了ValueError,float函数还会抛出其他的异常:
float((1,2))
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-8-a101b3a3d6cd> in <module>()
----> 1 float((1,2))
TypeError: float() argument must be a string or a number, not 'tuple'
可能你只是想处理ValueError,因为TypeError(输入的不是字符串或数值)可能表明你的程序中一个合乎语法的错误,为了实现这个目的,可以在except后面写下异常类型:
def float_2(x):
try:
return float(x)
except (TypeError,ValueError):
return x
然后我们可以得到:
float_2((1,2))
(1, 2)
你可以通过将多个异常类型写成元组的方式同时捕获多个异常(小括号是必不可少的)
在某些情况下,你可能想要处理一个异常,但是你希望一部分代码无论try代码块是否报错都要执行。为了实现这个目的,可以使用finally关键字:
f = open(path,'w')
try:
write_to_file(f)
finally:
f.close()
这样,我们就可以让f在程序结束后总是关闭。同样我们也可以使用else来当执行try代码块成功执行时才会执行的代码:
f = open(path,'w')
try:
write_to_file(f)
except:
print('Failed')
else:
print('Succeeded')
finally:
f.close()
IPython中的异常
如果当你正在用%run执行一个脚本或者执行任何语句时报错,IPython将会默认打印出完整的调用堆栈跟踪(报错追溯),会将堆栈中每个错误点附近的几行上下文代码打印出。
比标准的Python解释器提供额外的上下文是IPython的一大进步(标准Python解释器不提供任何额外的上下文)。你可以使用%xmode命令来控制上下文的数量,可以从Plain(普通)模式(与标准Python解释器一致)切换到Verbose(复杂)模式(可以显示函数的参数值以及更多有用信息),还可以使用%debug或%pdb命令来进行交互式事后调试。