python编程之异常处理
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子句(tryand except关键字之间的语句)。
如果没有异常发生,则将跳过except子句,并且该try语句的执行 完成。
如果在try子句执行期间发生异常,则该子句的其余部分将被跳过。然后,如果其类型与以except关键字命名的异常匹配 ,则执行except子句。
如果发生与except子句中命名的异常不匹配的异常,则将其传递给外部try语句。
try 语句的工作原理如下:
-
首先,执行try子句(tryand except关键字之间的语句)。
-
如果没有异常发生,则将跳过except子句,并且该try语句的执行 完成。
-
如果在try子句执行期间发生异常,则该子句的其余部分将被跳过。然后,如果其类型与以except关键字命名的异常匹配 ,则执行except子句。
-
如果发生与except子句中命名的异常不匹配的异常,则将其传递给外部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 zeroZeroDivisionError('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:指定将异常传播轨迹信息输出到指定文件中。如果不指定该参数,则默认输出到控制台。
mport traceback try: 1 / 0except: print(traceback.print_exc()) --------------------------------------------------------------运行结果:NoneTraceback (most recent call last): File "E:/github-projects/python-test/python_basics/traceback_test.py", line 16, in <module> 1 / 0ZeroDivisionError: division by zero