在我们写程序过程中,往往不是一次性就能写出很好的代码,会因为各种问题,程序发生错误
因此我们在写代码的时候,往往会花很多时间在错误处理上。一种方法是我们自己定义错误码,根据返回的错误码,来进行相对应的操作。
如:
def function():
r = some_return_value()
if r==(-1):
return (-1)
# do something
return r
然而这样的处理十分复杂,我们需要加很多后处理。python
中有异常处理try...except...finally...
的错误处理机制。
比如,对于一个数除以0:
try:
print('try...')
r = 1 / 0
print('result is:', r)
except ZeroDivisionError as e:
print('except:', e)
finally:
print('finally...')
print('END')
当我们认为某些代码可能会出错时,就可以用try
来运行这段代码,如果执行出错,则后续代码不会继续执行,而是直接跳转至错误处理代码,即except
语句块,执行完except
后,如果有finally
语句块,则执行finally
语句块,至此,执行完毕。
上述代码输出内容为:
try...
except: division by zero
finally...
END
当错误发生时,后续语句print('result:', r)
不会被执行,except
由于捕获到ZeroDivisionError
,因此被执行。最后,finally
语句被执行。然后,程序继续按照流程往下走。
如果我们把0换成了2,那么结果为:
try...
result: 5
finally...
END
由于没有错误发生,所以except
语句块不会被执行,但是finally
如果有,则一定会被执行(可以没有finally
语句)。
错误应该有很多种类,如果发生了不同类型的错误,应该由不同的except
语句块处理。没错,可以有多个except
来捕获不同类型的错误。此外,如果没有错误发生,可以在except
语句块后面加一个else
,当没有错误发生时,会自动执行else语句:
try:
print('try...')
r = 10 / int('2')
print('result:', r)
except ValueError as e:
print('ValueError:', e)
except ZeroDivisionError as e:
print('ZeroDivisionError:', e)
else: #没有异常时执行此段代码
print('no error!')
finally:
print('finally...')
print('END')
也就是说,不需要在每个可能出错的地方去捕获错误,只要在合适的层次去捕获错误就可以了。这样一来,就大大减少了写try...except...finally
的麻烦。我们可以用一张图来总结下try...except...else...finally
的执行顺序:
同时,Python中内置的错误有这些:
Python 使用 raise 语句抛出一个指定的异常。 如下抛出一个异常:
x = 10
if x > 5:
raise Exception('x 不能大于 5。x 的值为: {}'.format(x))
则以上的代码就会抛出一个异常:
Traceback (most recent call last):
File "test.py", line 3, in <module>
raise Exception('x 不能大于 5。x 的值为: {}'.format(x))
Exception: x 不能大于 5。x 的值为: 10
因为错误是class
,捕获一个错误就是捕获到该class
的一个实例。因此,错误并不是凭空产生的,而是有意创建并抛出的。Python
的内置函数会抛出很多类型的错误,我们自己编写的函数也可以抛出错误。
目前抛出的错误都是系统中实现的错误,如果要抛出一个我们自己想要设计的错误,首先根据需要,可以定义一个错误的class
,选择好继承关系,然后,用raise
语句抛出一个错误的实例:
# err_raise.py
class MyError(ValueError):
pass
def foo(s):
n = int(s)
if n==0:
raise MyError('invalid value: %s' % s)
return 10 / n
foo('0')
执行代码,则可以在最后跟踪到我们自定义的错误:
$ python3 err_raise.py
Traceback (most recent call last):
File "err_throw.py", line 11, in <module>
foo('0')
File "err_throw.py", line 8, in foo
raise FooError('invalid value: %s' % s)
__main__.FooError: invalid value: 0
只有在必要的时候才定义我们自己的错误类型。如果可以选择Python
已有的内置的错误类型(比如ValueError,TypeError
),尽量使用Python
内置的错误类型。
我们也可以嵌套异常处理,当我们当前函数无法很好的处理异常的时候,我们可以把异常再往上raise
,如代码:
try:
10 / 0
except ZeroDivisionError:
raise ValueError('input error!')
我们就可以把除以0的异常往值错误这样更宽泛错误上进行抛。
在python中,assert可以用于判断一个表达式,在表达式条件为false的时候触发异常。 断言可以在条件不满足程序运行的情况下直接返回错误,而不必等待程序运行后出现崩溃的情况,例如我们的代码只能在Linux 系统下运行,可以先判断当前系统是否符合条件。 代码举例:
>>> assert 1 == 1 #条件为True,则正常执行
>>> assert 1 == 2, '1不等于2'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AssertionError: 1 不等于 2
或者如我们判别当前是不是linux系统:
>>> import sys
>>> assert ('linux' in sys.platform), '非linux系统'
>>> ...#其它代码
在调试代码的时候,我们可以先用assert
来判断代码是否正常,如果不正常,assert
可以退出程序,再进行排查。再来,我们可以用try ... except
配合raise
的机制来进行代码的异常处理。