1、异常处理概念
程序运行过程中如果发生错误(包括语法错误和异常),程序就会用回溯(traceback)来终止执行。通过python解释器来捕获异常,处理异常来实现程序继续运行。
语法错误:也称为解析错误,顾名思义就是代码语法错误,不符合解释器或者编译器语法,比如我们刚学python的时候经常遇到的错误 SyntaxError
异常:代码的语法是正确的,但是由于不合法的输入值等因素造成的程序运行错误,如被除数是0会引发 ZeroDivisionError 类型的错误。
异常是python对象
2、内置异常
官网地址:Built-in Exceptions — Python 3.11.3 documentation
异常名称 | 描述 |
---|---|
BaseException | 所有异常的基类 |
SystemExit | 解释器请求退出 |
KeyboardInterrupt | 用户中断执行(通常是输入^C) |
GeneratorExit | 生成器(generator)发生异常来通知退出 |
Exception | 常规错误的基类 |
StopIteration | 迭代器没有更多的值 |
StandardError | 所有的内建标准异常的基类 |
ArithmeticError | 所有数值计算错误的基类 |
FloatingPointError | 浮点计算错误 |
OverflowError | 数值运算超出最大限制 |
ZeroDivisionError | 除(或取模)零 (所有数据类型) |
AssertionError | 断言语句失败 |
AttributeError | 对象没有这个属性 |
EOFError | 没有内建输入,到达EOF 标记 |
EnvironmentError | 操作系统错误的基类 |
IOError | 输入/输出操作失败 |
OSError | 操作系统错误 |
WindowsError | 系统调用失败 |
ImportError | 导入模块/对象失败 |
LookupError | 无效数据查询的基类 |
IndexError | 序列中没有此索引(index) |
KeyError | 映射中没有这个键 |
MemoryError | 内存溢出错误(对于Python 解释器不是致命的) |
NameError | 未声明/初始化对象 (没有属性) |
UnboundLocalError | 访问未初始化的本地变量 |
ReferenceError | 弱引用(Weak reference)试图访问已经垃圾回收了的对象 |
RuntimeError | 一般的运行时错误 |
NotImplementedError | 尚未实现的方法 |
SyntaxError | Python 语法错误 |
IndentationError | 缩进错误 |
TabError | Tab 和空格混用 |
SystemError | 一般的解释器系统错误 |
TypeError | 对类型无效的操作 |
ValueError | 传入无效的参数 |
UnicodeError | Unicode 相关的错误 |
UnicodeDecodeError | Unicode 解码时的错误 |
UnicodeEncodeError | Unicode 编码时错误 |
UnicodeTranslateError | Unicode 转换时错误 |
Warning | 警告的基类 |
DeprecationWarning | 关于被弃用的特征的警告 |
FutureWarning | 关于构造将来语义会有改变的警告 |
OverflowWarning | 旧的关于自动提升为长整型(long)的警告 |
PendingDeprecationWarning | 关于特性将会被废弃的警告 |
RuntimeWarning | 可疑的运行时行为(runtime behavior)的警告 |
SyntaxWarning | 可疑的语法的警告 |
UserWarning | 用户代码生成的警告 |
3、异常处理
3.1 try...except...语句
语法格式:
try:
"代码块"
except ExceptionName:
"捕获指定类型的异常,执行此代码块"
except Exception:
"捕获异常,执行此代码块"
try 语句的工作原理如下:
说明:
-
一个
try
语句可能有多个 except 子句,以指定不同异常的处理程序 -
except 后面可以是一个类型异常类型,也可以是多个异常类型,使用()括起来。
-
except 后面不接异常类型,会捕获所有异常。
-
也可以使用 as 给异常类型起别名,方便在异常处理代码块中调用。
-
try...except...可以是嵌套结构
实例:
try:
a = 1/0
except ZeroDivisionError as e:
# 捕获到异常的时候执行此代码块
print('捕获到异常啦!')
print(e)
except:
print('未知错误')
------------------------------------------------------------------
运行结果:
捕获到异常啦!
division by zero
3.2 else 语句
语法格式:
try:
"代码块"
except Exception:
"捕获异常,执行此代码块"
else:
"没有异常,执行此代码块"
说明:
-
else 语句只有当try代码块没有异常,并且执行完之后执行。
实例:
try:
assert 1 == 1
except:
print('捕获到异常啦!')
else:
# 没有捕获异常的时候执行此代码块
print("程序正常运行")
---------------------------------------------------------------
运行结果:
程序正常运行
3.3 finally 语句
语法格式:
try:
"代码块"
except Exception:
"捕获异常,执行此代码块"
else:
"没有异常,执行此代码块"
finally:
"无论是否捕获异常都会执行的代码块"
说明:
-
无论 try 块是否发生异常,都会执行 finally 语句的代码块
-
finally 在我们操作文件的时候很有用,无论是打开还是编辑文件之后都要执行保存文件的操作,起到释放资源的作用。
实例:
try:
assert 1 == 2
except (AssertionError,ZeroDivisionError) :
print('捕获到异常啦!')
except:
print('未知错误')
else:
print('程序正常运行')
finally:
print("程序继续运行")
--------------------------------------------------------------------
运行结果:
捕获到异常啦!
程序继续运行
4、主动抛出异常
raise 关键字允许我们在程序中手动抛出异常
语法:raise exceptName(reason)
try:
a = input("输入一个数:")
#判断用户输入的是否为数字
if(not a.isdigit()):
raise ValueError("a 必须是数字")
except ValueError as e:
print("发生异常:",repr(e))
------------------------------------------
运行结果:
输入一个数:aaa
发生异常: ValueError('a 必须是数字')
说明:
-
raise 抛出的异常,也可以用 except 去捕获异常
-
raise 抛出的异常可以是内置的异常,也可以是自定义的异常
5、自定义异常
-
用户自定义异常类需要继承 Exception 类,重写父类的__init__方法
# 自定义异常类 MyException
class MyException(Exception): # 继承异常类
def __init__(self,code,msg): # 重写父类的__init__方法
self.code = code
self.msg = msg
# 捕获自定义异常类并打印输出异常信息
try:
raise MyException('404','请求失败')
except MyException as e:
print(e)
-------------------------------------------
运行结果:
('404', '请求失败')
6、异常信息传递过程
def fun1():
fun2()
def fun2():
fun3()
def fun3():
raise Exception("抛出异常,可以自定义异常")
fun1()
--------------------------------------------------------------------
运行结果:
Traceback (most recent call last):
File "E:/github/python/python_module/traceback_module/exception_test.py", line 16, in <module>
fun1()
File "E:/github/python/python_module/traceback_module/exception_test.py", line 8, in fun1
fun2()
File "E:/github/python/python_module/traceback_module/exception_test.py", line 11, in fun2
fun3()
File "E:/github/python/python_module/traceback_module/exception_test.py", line 14, in fun3
raise Exception("抛出异常,可以自定义异常")
Exception: 抛出异常,可以自定义异常
-
分析运行结果可以看出,异常从fun3()函数开始触发,传到 fun2()函数,再传到 fun1()函数,最后传到最外层,这个过程就是整个异常的传播轨迹。
-
这样我们以后快速定位报错问题,只要看最后一个报错位置就行,再也不用怕控制台一堆报错信息。
7、打印异常信息
try:
a = 1/0
except (AssertionError,ZeroDivisionError) as e:
print("异常信息")
print(e)
print(e.args)
print(str(e))
print(repr(e))
except:
print('未知错误')
-----------------------------------------------
运行结果:
异常信息
division by zero
('division by zero',)
division by zero
ZeroDivisionError('division by zero')
说明
-
args:返回异常的错误编号和描述字符串;
-
str(e):返回异常信息,但不包括异常信息的类型;
-
repr(e):返回较全的异常信息,包括异常信息的类型。
8、回溯
8.1 使用 sys 模块中的 exc_info 方法
import sys
try:
1 / 0
except:
print(sys.exc_info())
-------------------------------------------------------------------
运行结果:
(<class 'ZeroDivisionError'>, ZeroDivisionError('division by zero'), <traceback object at 0x00000291DA2A8980>)
说明:
sys.exc_info( )的返回值是一个元组(type, value, traceback),其中:
-
type —— 异常的类型
-
value —— 异常的信息或者参数
-
traceback —— 包含调用栈信息的对象
8.2 使用 traceback 模块中的相关函数
-
语法格式:traceback.print_exc(limit=None, file=None)
-
limit:用于限制显示异常传播的层数
-
file:指定将异常传播轨迹信息输出到指定文件中。如果不指定该参数,则默认输出到控制台。
import traceback
try:
1 / 0
except:
print(traceback.print_exc())
--------------------------------------------------------------
运行结果:
None
Traceback (most recent call last):
File "E:/github-projects/python-test/python_basics/traceback_test.py", line 16, in <module>
1 / 0
ZeroDivisionError: division by zero
reference: