错误和异常
# 错误和异常
异常有很多种类型,Python 内置了几十种常见的异常,就在 builtins 模块内,无需特别导入,直接就可使用。需要注意的是,所有的异常都是异常类,首字母是大写的。
为了保证程序的正常运行,提高程序健壮性和可用性。我们应当尽量考虑全面,将可能出现的异常进行处理,而不是留在那里,任由其发生。
# Python 中处理异常
# 基本语法
Python 内置了一套 try...except 的异常处理机制,来帮助我们进行异常处理。其基本语法是:
try:
...
except AttributeError as e:
...
except ValueError as e:
...
2
3
4
5
6
其工作顺序是:
- 首先,执行
try
子句。 - 如果没有异常发生,则不执行
except
里面的代码,并执行try
里面剩下的代码。 - 如果在执行
try
里面代码时发生了异常,则不再执行剩下代码:- 如果抛出异常的类型和
except
的异常类匹配,则执行except
里面的代码。 - 如果抛出的异常没有被
except
的异常类匹配上,则直接抛出原生异常,在控制台打印。
- 如果抛出异常的类型和
# 多个 except 和 else
为了更精准的捕获异常并做出恰当的处理,一般会编写多个 except 和 else:
import sys
try:
...
except OSError as e:
...
except ValueError as e:
...
except:
print("Unexpected error:", sys.exc_info()[0])
raise
else:
print("没异常才执行")
2
3
4
5
6
7
8
9
10
11
12
13
- 最后一个
except
不指定异常类时,可以作为通配符,若前面所有异常类都没有匹配上,则会自动匹配这个except
,并执行里面代码,注意:最好要raise
一下,否则不知道异常是什么。 - 如果写
else
必须放在所有except
后面。 else
的作用:当try
里面的代码没有异常时就执行else
里面的代码,可以理解成:try
里面写有可能发生异常的代码块,而else
里面写若无异常则正常执行的代码块。
# finally
finally 里面的代码块,无论是否报异常都会执行:
import sys
try:
...
except OSError as e:
...
except ValueError as e:
...
except:
print("Unexpected error:", sys.exc_info()[0])
raise
else:
print("没异常才执行")
finally:
print("无论是否报异常都会执行")
2
3
4
5
6
7
8
9
10
11
12
13
14
15
finally 的作用:一般写清理关闭操作,如关闭文件、关闭数据库连接等等。
执行顺序:
- 若没有 break、continue、return、异常,执行顺序是:try -> else -> finally
- try 里面有 break、continue、return,在执行 break、continue、return 前也得执行 finally 代码块,且不执行 else 代码块。
- 若 try 和 finally 里面都有 return ,则优先执行 finally 的 return。
# 通用异常:Exception
在 Python 的异常中,有一个通用异常:Exception
,它可以捕获任意异常。
try:
...
except Exception as e:
print('错误')
2
3
4
- 所有内置的非系统退出类异常都继承自此类
- 所有自定义异常类都应该继承此类
# 常见异常类
Python 内置了很多的异常类,并且这些类都是从 BaseException
类派生的。
下面是一些常见异常类,在见到大多数异常的时候根据它们就能快速准确地判断异常类型:
异常名 | 解释 |
---|---|
AttributeError | 试图访问一个对象没有的属性 |
IOError | 输入/输出异常 |
ImportError | 无法引入模块或包;多是路径问题或名称错误 |
IndentationError | 缩进错误 |
IndexError | 下标索引错误 |
KeyError | 试图访问不存在的键 |
KeyboardInterrupt | Ctrl+C 被按下,键盘终止输入 |
NameError | 使用未定义的变量 |
SyntaxError | 语法错误 |
TypeError | 传入对象的类型与要求的不符合 |
UnboundLocalError | 试图访问一个还未被设置的局部变量 |
ValueError | 传入一个调用者不期望的值,即使值的类型是正确的 |
OSError | 操作系统执行错误 |
# 自定义异常
大多数情况下,内置异常已经够用了,但是有时候你还是需要自定义一些异常。自定义异常应该继承 Exception
类,直接继承或者间接继承都可以,例如:
在 Python 3 中,大多数异常类已经移除了
.message
属性,因此需要手动实现该参数的传递,并重写__str__
方法
class CustomException(Exception):
def __init__(self, message):
"""
:param message: 异常信息
"""
self.message = message
super().__init__()
# override
def __str__(self):
return self.message
try:
raise CustomException('我的异常!')
except CustomException as e:
print(e)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
异常的名字都以 Error
结尾,所以在实际开发中,我们在为自定义异常命名的时候也需要遵守这一规范,就跟标准的异常命名一样。
# 主动抛出异常:raise
很多时候,我们需要主动抛出一个异常。Python 内置了一个关键字 raise
,可以主动触发异常。
raise 唯一的一个参数指定了要被抛出的异常的实例,如果什么参数都不给,那么会默认抛出当前异常。
一般用到 raise 主要是为了记录错误信息,然后将异常继续往上层传递,让上层去处理异常:
try:
1/0
except ZeroDivisionError as e:
print("记录异常日志:", e)
print("但是我自己无法处理,只能继续抛出,看看上层能否处理")
raise
2
3
4
5
6
有时候,你需要主动弹出异常,作为警告或特殊处理:
sex = int(input("Please input a number: "))
try:
if sex == 1:
print("这是个男人!")
elif sex == 0:
print("这是个女人!")
else:
print("好像有什么不符合常理的事情发生了!!")
raise ValueError("非法的输入")
except ValueError:
print("这是个什么物种!")
2
3
4
5
6
7
8
9
10
11
12
更多的时候,你需要使用 raise 抛出你自定义的异常。
(完)