引言
在编写Python程序时,有时我们不确定一段语句是否可以正确执行,因为如果发生错误,那么程序就会终止,这样对完整代码实现很不友好。我们希望可以程序可以根据不同的错误(异常)从而执行不同的语句,达到解决错误的效果。
1. try…except…else…finally…语句
1.1 语法
为了捕获异常,在编码过程中,我们可以简单使用 try/except 语句来捕捉异常,具体语法如下:
try: # 尝试运行的语句(可能会发生异常,也可能不会发生异常)
<语句>
except (异常类型1, 异常类型2, ...): # 如果发生异常类型1时的操作
<语句>
else: # 如果没有发生异常的操作(可选)
<语句>
finally: # 不管有没有发生异常都会执行的操作
<语句>
上面的代码实现了:通过监视 try 语句块中的错误,从而让 except 语句捕获异常信息并进行处理。因此,如果你不想在异常发生时结束你的程序,就需要在 try 语句块中捕获相应的异常。
1.2 try的工作原理
- try 的工作原理是,当开始一个 try 语句后,python 就在当前程序的上下文中作标记,这样当异常出现时就可以回到这里,try 子句先执行,接下来会发生什么依赖于执行时是否出现异常。
- 大致的情况可以分为两种,一种是触发了异常,另一种是没有触发异常,具体表现如下:如果当 try 后的代码里发生了异常,python 就跳回到 try 并执行第一个匹配该异常的 except 子句,异常处理完毕,控制流就通过整个 try 语句。如果在 try 后的代码里没有发生异常,python将执行else语句后的语句,然后控制流通过整个try语句。
2.主动抛出异常 —— raise
我们从来都是想方设法地让程序正常运行,为什么还要手动设置异常呢?首先要分清楚程序发生异常和程序执行错误,它们完全是两码事:
程序由于错误导致的运行异常,是需要程序员想办法解决的 —— 一般使用try…except…语句或者直接debug
但还有一些异常,是程序正常运行的结果,比如用 raise 手动引发的异常。
2.1语法
raise 语句的基本语法格式为:raise [exceptionName [(reason)]]
其中, exceptionName和reason 为均可选参数,前者的作用是指定抛出的异常名称,后者为异常信息的相关描述。
- 如果可选参数全部省略,则 raise 会把当前错误原样抛出
- 如果仅省略 (reason),则在抛出异常时,将不附带任何的异常描述信息
也就是说,raise 语句有如下三种常用的用法:
- raise:单独一个 raise。该语句引发当前上下文中捕获的异常(比如在 except 块中),或默认引发 RuntimeError 异常。
- raise exceptionName:raise 后带一个异常类名称,表示引发执行类型的异常。
- raise exceptionName(reason):在引发指定类型的异常的同时,附带异常的描述信息。
显然,每次执行 raise 语句,都只能引发一次执行的异常。首先,我们来测试一下以上 3 种 raise 的用法:
>>> # 1. 单独一个raise
>>> raise
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
RuntimeError: No active exception to reraise
>>> # 2. raise exceptionName
>>> raise ZeroDivisionError
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ZeroDivisionError
>>> raise NoArgumentsError
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'NoArgumentsError' is not defined # exception需要符合规定,不行自己乱写
>>> NoArgumentsError = "没有参数异常"
>>> raise NoArgumentsError
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: exceptions must derive from BaseException # exception需要符合规定,不行自己乱写
>>> raise Exception("NoArgumentsError")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
Exception: NoArgumentsError
>>> # 3. raise exceptionName(reason)
>>> raise ZeroDivisionError("除零错误!")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ZeroDivisionError: 除零错误
2.2使用raise的目的
我们手动让程序引发异常,很多时候并不是为了让其崩溃。事实上,raise 语句引发的异常通常用 try except (else finally)异常处理结构来捕获并进行处理。
虽然程序中使用了 raise 语句引发异常,但程序的执行是正常的,手动抛出的异常经过合适的处理并不会导致程序崩溃。
# raise默认引发的异常
try:
num = input("请输入一个数字:")
if not num.isdigit():
raise
else:
print(f"输入为: {num}")
except RuntimeError as e:
print(f"异常[{e}]触发")
"""
请输入一个数字:leovin
异常[No active exception to reraise]触发
"""
#---------------------------------------------------------------------------------------------------------------
# 不指定except需捕获的异常
try:
num = input("请输入一个数字:")
if not num.isdigit():
raise
else:
print(f"输入为: {num}")
except:
print(f"异常触发") # 但这样我们就不知道具体是什么异常发生了!
"""
请输入一个数字:leovin
异常触发
"""
总结
- try:正常情况下,程序计划执行的语句
- except:程序异常时执行的语句
- else:程序无异常即try段代码正常执行后会执行该语句
- finally:不管有没有异常,都会执行的语句
1.无论有无异常,finally代码段一定会被执行
2.若有异常,则执行except代码段
3.若无异常且无return,则执行else代码段
4.若无异常且有return,try代码段中有return语句,则else代码段不会被执行
5.若无异常且有return,try代码段没有return语句,则else代码段会执行