Python 中的异常处理机制

在程序运行过程中,总会遇到各种各样的错误,这会使得程序运行结果和预期不符,严重时甚至会导致程序奔溃。

在编码过程中使用合理的 异常处理机制,可以帮助程序在运行出现错误时,捕获并且并处理这些错误,进而尝试恢复程序的执行,或者进行一些程序崩溃前的必要工作(如内存中的数据写入文件等)。异常处理机制对于编写一个良好的、健壮的程序是至关重要的。

异常引入

开发人员在编写程序时,难免会遇到各种各样的错误。

有的错误是编写人员疏忽造成的语法错误,比如缩进错误,语法格式使用错误等,这种错误是必须修复的。

有的错误是程序内部隐含逻辑问题造成的数据错误(调试时很方便检出),这种错误需要仔细分析相应的逻辑流程进行处理。

有的错误是由于用户输入造成的数据错误,比如让用户输入 URL 地址,结果得到一个空字符串,这种错误可以通过检查用户输入来做相应的处理。

还有一类错误是程序运行时与系统的规则冲突造成的系统错误,完全无法在程序运行过程中预测的,比如写入文件的时候,磁盘满了,写不进去了;或者从网络抓取数据,网络突然断掉了等等。这种错误在程序中通常是必须处理的,否则,程序会因为各种问题终止并退出。

总的来说,Python 中编写程序时遇到的错误可大致分为两类:

  1. 语法错误;
  2. 运行时错误。

语法错误

语法错误,是指解析代码时出现的错误。

当代码不符合 Python 语法规则时,Python 解释器在解析时就会报出 SyntaxError 语法错误,与此同时还会明确指出最早解析到错误的语句。

例如,Python 3 中已不再支持下面这种写法,运行时,解释器会报错误:

1
2
3
4
5
6
print "Hello,World!"

# File "<stdin>", line 1
# print "Hello,World!"
# ^
# SyntaxError: Missing parentheses in call to 'print'.

除此之外,其它 常见的语法错误类型如下表 >>>>

错误类型 含义
SyntaxError:unexpected EOF while parsing 语法错误:多了无法解析的符号,检查是否多了或者少了括号。
SyntaxError:invalid character in identifier 有无效标识符,检查一下是否使用中文符号。
SyntaxError -> IndentationError: expected an indented block 解析时缩进错误:检查一下代码的缩进是否正确。

语法错误多是开发者疏忽导致的,属于真正意义上的错误,是解释器无法容忍的,只有将程序中的所有语法错误全部纠正,程序才能执行。

需要注意的是 >>>>

语法错误并不需要异常处理机制的参与,它由开发人员自己保证,我们更关注的是程序运行时产生的错误(异常)。


运行时异常

运行时异常,即程序在语法上都是正确的,但在运行时发生了错误。

实例演示:

1
2
3
4
5
a = 1/0
# Traceback (most recent call last):
# File "<pyshell#2>", line 1, in <module>
# a = 1/0
# ZeroDivisionError: division by zero

可以看到,用 1 除以 0,并赋值给 a 。因为 0 作除数是没有意义的,所以运行后会产生 ZeroDivisionError 错误。在输出结果中,前两段指明了错误的位置,最后一句表示出错的类型。

Python 中,把这种运行时产生错误的情况叫做 异常(Exceptions)。除此以外,Python 中异常情况包括很多种类,常见错误类型接下文。


常见异常类型

Python 中的错误类型也是类,它们都是从 BaseException 类派生的,常见见下表。更多的错误类型和其继承关系请参见:Exception hierarchy

错误类型 具体 含义
IndexError list index out of range 索引错误:数据超出索引范围,检查一下是否数据使用越界。
TypeError must be str, not int … 数据类型错误:不同类型数据之间的无效操作。比如字符串和数字直接拼接,此时检查一下数据类型是否使用错误。
KeyError KeyError:’fond’ 键错误:字典中没有该的 key(“fond”)对应的值,检查一下键名或者字典数据是否正确。
ValueError substring not found 值错误:输入的数据类型跟要求的不符合。
NameError name ‘a’ is not defined 未初始化对象:变量没有被定义就使用了,或者变量被删除后再次使用。
AttributeError ‘tuple’ object has no attribute ‘remove’ 对象属性错误:当试图访问的对象属性不存在时抛出的异常
SystemExit SystemExit 解释器请求退出,出现在 exit() 函数后。
IOError IOError 输入/输出操作失败
ImportError ModuleNotFoundError 导入模块/对象失败,检查一下模块是否存在或者能够正常使用。
UnicodeError UnicodeDecodeError / UnicodeEncodeError / UnicodeTranslateError Unicode 解码/编码/转换/时的错误:请检查字符解码/编码/转换。
AssertionError AssertionError 当 assert 关键字后的条件为假时,程序运行会停止并抛出 AssertionError 异常

引入异常处理机制

当一个程序发生异常时,代表该程序在执行时出现了非正常的情况,无法再执行下去。默认情况下,程序是要终止的。

什么?!!你说你编写的程序不会出错?

请记住,无论你是多么优秀的程序员,你都不能保证自己的程序永远不会出错。就算你的程序没有错,用户也不一定按照你设定的规则来使用你的程序,总有一些小白或者极客会“玩弄”你的程序。

除此以外,你也不能保证程序的运行环境永远稳定,比如网络可能无法连接,磁盘写满 ……

总之,你只可以保证你的程序语法正确(?),其它的…

但是,作为一个负责任的程序员,我们要让自己的程序尽可能的健壮 >>>> 代码要有异常处理

即,当程序运行过程中异常产生后,可以使用捕获异常的方式获取这个异常的名称,再通过其他的逻辑代码尝试恢复程序的执行,或者进行一些程序崩溃前的必要工作,这种根据异常做出相应逻辑处理的过程叫作 异常处理

自然而然的引发一个问题 >>>>

那么,应该如何捕获和处理异常呢???

幸运的时,所有的高级语言通常都内置了一套 try...except...finally... 用于捕获以及处理异常的 异常处理机制,Python 当然也不例外。


异常处理机制是现代编程语言不可或缺的能力,它已经成为衡量一门编程语言是否成熟和健壮的标准之一。

Python 中的异常处理机制

先来看 Python 中的基本异常处理结构:try except 语句块,它是 Python 异常处理机制的核心结构。

try except 异常处理

Python 中,使用 try except 语句块捕获并处理异常的基本语法结构如下:

1
2
3
4
5
6
7
8
9
try:
# 可能产生异常的代码块

except [ (Error1, Error2, ... ) [as e] ]:
# 处理异常的代码块1
except [ (Error3, Error4, ... ) [as e] ]:
# 处理异常的代码块2
except [Exception]:
# 处理其它异常

[1] >>>> 语法结构说明

关于 try except 语法结构说明分为两个部分:结构说明 && 参数说明。

1)–> 结构说明

try except 结构中,try 块有且仅有一个,但 except 代码块可以有多个(>=0),并且每个 except 块都可以同时处理多种异常。

注意,except 代码块至少要有一个(没有 finally 块时,见后文),否则会产生语法错误(SyntaxError):

1
2
3
# SyntaxError: invalid syntax
# 或者
# SyntaxError: unexpected EOF while parsing

2)–> 参数说明

[] 括起来的参数部分可以选择使用,也可以省略。其中各部分的含义如下:

  • (Error1, Error2,…) 、(Error3, Error4,…):其中,Error1、Error2、Error3 和 Error4 都是具体的异常类型(参见常见异常类型)。显然,一个 except 块可以同时处理多种异常;
  • [as e]:作为可选参数,表示给异常类型起一个别名 e,这样做的好处是方便在 except 块中调用异常类型;
  • [Exception]:作为可选参数,可以代指程序可能发生的所有异常情况,其通常用在最后一个 except 块。

[2] >>>> 执行流程说明

1)首先执行 try 中的代码块,如果执行过程中出现异常,系统会自动解析生成一个对应异常类型,并将该异常提交给 Python 解释器,此过程称为捕获异常。

2)当 Python 解释器收到异常对象时,会寻找能处理该异常对象的 except 块(取决于 except 语句中异常类型参数),如果找到合适的 except 块,则把该异常对象交给该 except 块处理,这个过程被称为处理异常。如果 Python 解释器找不到处理异常的 except 块,则程序运行终止,Python 解释器也将退出。

注意,如果此段程序没有用 try 包裹,又或者没有为该异常配置处理它的 except 块,则 Python 解释器将无法处理,程序就会停止运行;反之,不管程序代码块是否处于 try 块中,甚至包括 except 块中的代码,只要执行该代码块时出现了异常,系统都会自动解析生成对应类型的异常,捕获后由相应 except 处理完成,则程序可以继续执行。


来看一个实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
print("Begin To Run")
try:
a = int(input("输入被除数:"))
b = int(input("输入除数:"))
c = a / b
print("相除的结果是:", c )

except (ValueError, ArithmeticError): # 处理 ValueError & ArithmeticError 异常的 except 块
print("程序发生了数字格式异常、算术异常之一")
print("进行特定异常处理")

except : # 其它不确定异常(省略 Exception 参数)
print("未知异常")
print("进行异常处理")

print("Continue To Run")

程序运行结果为:

1
2
3
4
5
6
Begin To Run
输入被除数: 3
输入除数: 0
程序发生了数字格式异常、算术异常之一
进行特定异常处理
Continue To Run

可以看到,第一个 except 块使用(ValueError, ArithmeticError)来指定可以处理的异常类型,这就表明该 except 块可以同时处理这 2 种类型的异常;第二个 except 块使用省略异常类的 except 语句(except Exception),它并未指定具体要处理的异常类型,表示可处理所有类型的异常,一般会作为异处理的最后一个 except 块。

上面,由于 try 块中引发了异常,并被 Python 解释器捕获,并找到第一个 except 块可处理相应异常,处理后,程序继续执行,输出 Continue To Run


[3] >>>> 获取发生的特定异常相关信息

上面,我们已经可以捕获程序中可能发生的异常,并对其进行处理。

但是,由于一个 except 可以同时处理多个异常,那么我们如何知道当前处理的到底是哪种类型的异常呢?

事实上,每种异常类型都具有了如下几个属性和方法,通过调用它们,就可以获取当前处理异常类型的相关信息:

  • args:返回异常信息的描述字符串;
  • str(e):返回异常信息,但不包括异常信息的类型;
  • repr(e):返回较全的异常信息,包括异常信息的类型。

基于此,我们可以给捕获到的异常类型起一个别名 e(as e),就可以访问其属性输出相应异常信息了:

1
2
3
4
5
6
7
8
9
10
11
try:
1/0
except Exception as e:
# 访问异常的描述信息
print(e.args)
print(str(e))
print(repr(e))

# ('division by zero',)
# division by zero
# ZeroDivisionError('division by zero',)

从程序中可以看到,由于 except 可能接收多种异常,因此为了操作方便,直接给每一个进入到此 except 块的异常,起一个统一的别名 e。

注意,在 Python 2.x 的早期版本中,除了使用 as e 这个格式,还可以将其中的 as 用逗号 , 代替(即 exception Exception, as)。


深入解读异常处理块查找机制

我们知道,当位于 try 块中的程序执行出现异常时,会将该种异常捕获,同时找到对应的 except 块处理该异常。

那么这里就有一个问题,Python 解释器是如何找到对应的 except 块的呢???

[1] >>>> 异常类

我们知道,一个 try 块也可以对应多个 except 块,一个 except 块可以同时处理多种异常,并且如果我们想使用一个 except 块处理所有异常还可以使用省略异常类型的 except 关键字(或 Exception)。

你肯定困惑过,为什么 Exception 异常可以对应所有的异常处理???这就不得不提到异常类了。

事实上,异常也是类。为了表示程序中可能出现的各种异常,Python 提供了大量的异常类,这些异常类之间有严格的继承关系。如下(异常类详情请参见 Exception Hierarchy):

可以看出,BaseException 是 Python 中所有异常类的基类,但对于我们来说,最主要的是 Exception 类,因为程序中可能出现的各种异常,都继承自 Exception。

了解了异常类以及其继承关系之后,就可以开始解读异常处理块的查找机制了 >>>>

[2] >>>> 查找机制

当 try 块捕获到异常对象后,Python 解释器会拿这个异常类型依次和各个 except 块指定的异常类进行比较,如果捕获到的这个异常类,和某个 except 块后的异常类一样,又或者是该异常类的子类,那么 Python 解释器就会调用这个 except 块来处理异常。

反之,Python 解释器会继续比较,直到和最后一个 except 比较完,如果没有比对成功,则证明该异常无法处理。

异常处理块查找机制示意图如下所示:

简单的异常捕获的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
try:
a = int(input("输入被除数 a:"))
b = int(input("输入除数 b:"))
print( a/b )

except ValueError:
print("数值错误:程序只能接收整数参数")

except ArithmeticError:
print("算术错误:除数不能为 0")

except Exception:
print("未知异常")

该程序中,根据用户输入 a 和 b 值的不同,可能会导致 ValueError、ArithmeticError 异常:

  1. 如果用户输入的 a 或者 b 是其他字符,而不是数字,会发生 ValueError 异常,try 块会捕获到该类型异常,同时 Python 解释器会调用第一个 except 块处理异常;
  2. 如果用户输入的 a 和 b 是数字,但 b 的值为 0,由于在进行除法运算时除数不能为 0,因此会发生 ArithmeticError 异常,try 块会捕获该异常,同时 Python 解释器会调用第二个 except 块处理异常;
  3. 当然,程序运行过程中,还可能由于其他因素出现异常,try 块都可以捕获,同时 Python 会调用最后一个 except 块来处理。

[3] >>>> except 块异常类型定义规则

当一个 try 块配有多个 except 块时,这些 except 块应遵循这样一个排序规则,即可处理全部异常的 except 块(参数为 Exception,也可以省略)要放到所有 except 块的后面

并且,所有父类异常的 except 块要放到子类异常的 except 块的后面。这意味着,一旦父类放于前面,它不但捕获该类型的错误,还把其子类也“一网打尽”,会导致其子类的 except 块永远也无法执行到(无意义的 except 块)。

例如:

1
2
3
4
5
6
try:
foo()
except ValueError as e:
print('ValueError')
except UnicodeError as e:
print('UnicodeError')

第二个 except 永远也处理 UnicodeError 异常,因为 UnicodeError 是 ValueError 的子类,如果有,也被第一个 except 给处理了。


try except 通用形式

我们知道,try except 语句块结构是 Python 异常处理机制中的核心结构。

但在实际使用过程中,还可以根据实际需要在 try except 语句块结构基础上添加 else 块和 finally 块结构(都是可选的),这样就变为:

  • try except else 语句块结构
  • try except finally 语句块结构
  • try except else finally 语句块结构

try except else 异常处理

Python 异常处理还提供了一个 else 机制,也就是原有 try except 语句的基础上再添加一个 else 块,即 try except else 结构。

try except else 语句块结构如下:

1
2
3
4
5
6
7
8
9
try:
# 可能产生异常的代码块
except [ (Error1, Error2, ... ) [as e] ]:
# 处理异常的代码块
except [Exception]:
# 处理其它异常

else:
# 没有捕获异常时执行

注意:使用 else 包裹的代码,只有当 try 块没有捕获到任何异常时,才会得到执行;反之,如果 try 块捕获到异常,即便调用对应的 except 处理完异常,else 块中的代码也不会得到执行。

实例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
try:
result = 20 / int(input('请输入除数:'))
print(result)
except ValueError:
print('必须输入整数')
except ArithmeticError:
print('算术错误,除数不能为 0')
else:
print('没有出现异常')

print("Continue to run")
# 请输入除数: 4
# 5.0
# 没有出现异常
# Continue to run

你可能会困惑,既然 Python 解释器按照顺序执行代码,那么 else 块有什么存在的必要呢?直接将 else 块中的代码编写在 try except 块的后面,不是一样吗?

事实上,else 的功能,只有当 try 块捕获到异常时才能显现出来。在这种情况下,else 块中的代码不会得到执行的机会。如下运行:

1
2
3
# 请输入除数: "2"
# 必须输入整数
# Continue to run

try except finally 异常处理

Python 异常处理机制还提供了一个 finally 语句,通常用来为 try 块中的程序做扫尾清理工作。

try except finally 基本结构如下:

1
2
3
4
5
6
7
8
9
10
11
12
try:
# 可能产生异常的代码块
except [ (Error1, Error2, ... ) [as e] ]:
# 处理异常的代码块
except [Exception]:
# 处理其它异常

else:
# 没有捕获异常时执行

finally:
# 是否捕获到异常都需要执行

结构说明:和 else 语句不同,finally 只要求和 try 搭配使用,而至于该结构中是否包含 except 以及 else,对于 finally 都不是必须的(else 必须和 try except 搭配使用)。

在整个异常处理机制中,finally 语句块的功能是:无论 try 块是否发生异常,最终都要进入 finally 语句,并执行其中的代码块。

[1] >>>> finally 语句块作用

Python 垃圾回收机制,只能帮我们回收变量、类对象、函数等占用的内存,而无法自动完成类似关闭文件、数据库连接等这些的工作。

基于上述 finally 语句块的特性,在某些情况下,当 try 块中的程序打开了一些物理资源(文件、数据库连接等)时,由于这些资源必须手动回收,而回收工作通常就可以放在 finally 块中。

当然了,回收这些物理资源并不是必须使用 finally 块,但使用 finally 块是比较好的选择。

这是由于,try 块不适合做资源回收工作,因为一旦 try 块中的某行代码发生异常,则其后续的代码将不会得到执行;其次 except 和 else 也不适合,它们都可能不会得到执行;而 finally 块中的代码,无论 try 块是否发生异常,该块中的代码都会被执行。

[2] >>>> 演示实例

1
2
3
4
5
6
7
8
9
10
11
try:
a = int(input("请输入 a 的值:"))
print(20/a)
except:
print("发生异常!")

else:
print("执行 else 块中的代码")

finally :
print("执行 finally 块中的代码")

1)–> 正常运行此程序:

1
2
3
4
请输入 a 的值: 4
5.0
执行 else 块中的代码
执行 finally 块中的代码

可以看到,当 try 块中代码未发生异常时,except 块不会执行,else 块和 finally 块中的代码会被执行。

2)–> 运行中产生异常:

1
2
3
请输入 a 的值: 0
发生异常!
执行 finally 块中的代码

可以看到,当 try 块中代码发生异常时,except 块得到执行,而 else 块中的代码将不执行,finally 块中的代码仍然会被执行。

3)–> 程序异常退出情况

finally 块的强大还远不止此,即便当 try 块发生异常,且没有合适和 except 处理异常时,finally 块中的代码也会得到执行。例如:

1
2
3
4
5
6
7
8
9
10
11
12
try:
#发生异常
print(20/0)

finally :
print("执行 finally 块中的代码")

# 执行 finally 块中的代码
# Traceback (most recent call last):
# File "D:\python3.6\1.py", line 3, in <module>
# print(20/0)
# ZeroDivisionError: division by zero

可以看到,当 try 块中代码发生异常,导致程序崩溃时,在崩溃前 Python 解释器也会执行 finally 块中的代码。


try except else finally 异常处理通用形式

Python 通用的异常处理语法结构如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
try:
#业务实现代码
except Exception1 as e:
#异常处理块1
...
except Exception2 as e:
#异常处理块2
...
#可以有多个 except
...
else:
#正常处理块
finally :
#资源回收块
...

异常处理结构流程图如下:

整个异常处理结构中,只有 try 块是必需的,也就是说:

  • 如果没有 try 块,则不能有后面的 except 块、else 块和 finally 块。但是也不能只使用 try 块,要么使用 try except 结构,要么使用 try finally 结构;
  • except 块、else 块、finally 块都是可选的,当然也可以同时出现
  • 可以有多个 except 块,但捕获父类异常的 except 块应该位于捕获子类异常的 except 块的后面;
  • 多个 except 块必须位于 try 块之后,finally 块必须位于所有的 except 块之后。
  • 要使用 else 块,其前面必须包含 try 和 except。

程序退出情况下 finally 运行说明 >>>>

[1] >>>> break、continue、return 退出情况

finally 语句不管异常是否发生都会执行。不仅如此,无论是正常退出、遇到异常退出,还是通过 break、continue、return 语句退出,finally 语句块都会执行。

[2] >>>> 解释器退出(os._exit(1))情况

如果 try 块、except 块中调用了退出 Python 解释器的方法,则 finally 语句将无法得到执行。否则不管在 try 块、except 块中执行怎样的代码,出现怎样的情况,异常处理的 finally 块总会被执行。

实例演示:

1
2
3
4
5
import os
try:
os._exit(1)
finally:
print("执行finally语句")

运行程序,没有任何输出。

[3] >>>> return、raise 中止语句

尽量避免在 finally 块里使用 return 或 raise 等导致方法中止的语句,它将会导致 try 块、except 块中的 return、raise 语句失效。如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
def test():
try:
print("try 块")
# 因为 finally 块中包含了 return 语句
# 所以下面的 return 语句失去作用
return True
finally:
return False

print(test())

# try 块
# False

仔细思考一下,无论是否产生异常(不考虑解释器退出情况),finally 块均会执行。此时如果,try 块、except 块中包含 return、raise,而 finally 块也包含相应 return、raise 中止语句时,解释器到底该返回哪一个???

如果 Python 程序在执行 try 块、except 块包含有 return 或 raise 语句,则 Python 解释器执行到该语句时,会先去查找 finally 块,如果没有 finally 块,程序才会立即执行 return 或 raise 语句。

反之,如果找到 finally 块,系统立即开始执行 finally 块,只有当 finally 块执行完成后,系统才会再次跳回来执行 try 块、except 块里的 return 或 raise 语句。如果此时 finally 块里也使用了 return 或 raise 等导致方法中止的语句,finally 块己经中止了方法,系统将不会跳回去执行 try 块、except 块里的任何代码。


Raise 手动抛出异常

raise 语句的基本语法格式为:

1
raise [exceptionName [(reason)]]

说明,用 [] 括起来的为可选参数,其作用是指定抛出的异常类型的名称,以及相应异常的描述信息。如果可选参数全部省略,则 raise 会把当前 Python 解释器检测到的上下文错误原样抛出;如果仅省略 (reason),则在抛出指定异常时,将不附带任何的异常描述信息。

也就是说,raise 语句有如下三种常用的用法:

  • raise:可选参数全部缺省。该语句会把当前 Python 解释器自动检测到的上下文错误原样抛出,如没有检测到其它上下文异常则默认引发 RuntimeError 异常;
  • raise exceptionName:raise 后带一个异常类型名称,表示手动抛出一个指定的 exceptionName 类型的异常(该指定异常是 Python 内置的异常类型或用户自定义异常);
  • raise exceptionName(reason):在抛出指定类型异常的同时,附带异常的描述信息。

你可能会感到非常困惑,我们都是想方设法地让程序正常运行,为什么还要手动抛出异常呢???

通常情况下,手动让程序引发异常,很多时候并不是为了让其崩溃,而是针对程序运行中可能出现的异常进行手动捕获并处理。事实上,raise 语句引发的异常通常结合 try except(else finally)异常处理结构来捕获并进行处理。

实例演示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
while True:
try:
a = input("Please enter a number: ")
# 判断用户输入的是否为数字
if(not a.isdigit()):
raise ValueError("Input must be a number!!!")

break

except ValueError as e:
print("引发异常:", repr(e))

# Please enter a number: sdf3
# 引发异常: Input must be a number!!!
# Please enter a number: 22

程序执行时,当用户输入的不是数字时,程序会进入 if 判断语句,并执行 raise 引发 ValueError 异常。但由于其位于 try 块中,因为 raise 抛出的异常会被 try 捕获,并由 except 块进行处理。

可以看到,虽然程序中使用了 raise 语句引发异常,但程序的执行是正常的,手动抛出的异常并不会导致程序崩溃。

无参 raise >>>>

1)–> 上下文中已引发过异常

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
try:
a = input("Please enter a number: ")
# 判断用户输入的是否为数字
if(not a.isdigit()):
raise ValueError("Input must be a number!!!")

except ValueError as e:
print("引发异常:", repr(e))
raise

# Please enter a number: wer
# 引发异常: Input must be a number!!!
# Traceback (most recent call last)
# File "test.py", line 4, in <module>()
# ----> 5 raise ValueError("Input must be a number!!!")
# ValueError: Input must be a number!!!

这里重点关注位于 except 块中的 raise,由于在其之前我们已经手动引发了 ValueError 异常,因此这里当再使用 raise 语句时,它会再次引发一次。

2)–> 上下文中未引发过异常

需要注意的是,在没有引发过异常的程序使用无参的 raise 语句时,它默认引发的是 RuntimeError 异常。例如:

1
2
3
4
5
6
7
8
9
10
11
try:
a = input("Please enter a number: ")
# 判断用户输入的是否为数字
if(not a.isdigit()):
raise

except RuntimeError as e:
print("引发异常:", repr(e))

# Please enter a number: abc
# 引发异常: RuntimeError('No active exception to reraise',)
Author

Waldeinsamkeit

Posted on

2018-01-14

Updated on

2022-04-14

Licensed under

You need to set install_url to use ShareThis. Please set it in _config.yml.

Comments

You forgot to set the shortname for Disqus. Please set it in _config.yml.