您的“关注”和“点赞”,是信任,是认可,是支持,是动力…
如意见相佐,可留言。
本人必将竭尽全力试图做到准确和全面,终其一生进行修改补充更新。
文章目录
1 try except 详解
1.1 try except 概述
Python 中,用 try except
语句块捕获并处理异常。
当程序发生不同的意外情况时,会对应特定的异常类型,Python 解释器会根据该异常类型选择对应的 except 块来处理该异常。
注意:不管程序代码块是否处于 try 块中,甚至包括 except 块中的代码,只要执行该代码块时出现了异常,系统都会自动生成对应类型的异常。但是,如果此段程序没有用 try 包裹,又或者没有为该异常配置处理它的 except 块,则 Python 解释器将无法处理,程序就会停止运行;如果程序发生的异常经 try 捕获并由 except 处理完成,则程序可以继续执行。
基本语法结构如下所示:
try:
代码块1 # 可能产生异常的代码块,有且仅有一个
except [(Error1, Error2, ... ) [as e]]:
代码块2 # 处理异常的代码
except [(Error3, Error4, ... ) [as e]]:
代码块3 # 处理异常的代码
... # 可以有多个 except 块
except [Exception]:
代码块4 # 处理其他异常的代码
对以上格式说明,
[]
:中括号括起来的为可选内容,可有可无。(Error1, Error2,...) 、(Error3, Error4,...)
:都是具体的异常类型。一个 except 块可以同时处理多种异常。[as e]
:表示给异常类型起一个别名 e,这样做的好处是方便在 except 块中调用异常类型。[Exception]
:可以表示程序可能发生的所有异常情况,其通常用在最后一个 except 块。- try except 语句的执行流程如下所示,
(1)捕获异常:首先执行 try 中的代码块,如果执行过程中出现异常,系统会自动生成一个异常类型,并将该异常提交给 Python 解释器,此过程称为捕获异常。
(2)处理异常:当 Python 解释器收到异常对象时,会寻找能处理该异常对象的 except 块,如果找到合适的 except 块,则把该异常对象交给该 except 块处理,这个过程被称为处理异常。
(3)终止程序:如果 Python 解释器找不到处理异常的 except 块,则程序运行终止,Python 解释器也将退出。
举例如下所示:
例一,正常情况
try:
# 可能出现异常的代码块
a = int(input("请输入被除数:"))
b = int(input("请输入除数:"))
c = a / b
print("相除的商为:", c)
except (ValueError, ArithmeticError): # ZeroDivisionError 是 ArithmeticError 的子类
# 处理异常的代码块
print("程序发生了数字格式异常、算术异常之一")
except : # 未指定具体要捕获的异常类型,这种省略异常类的 except 语句也是合法的,它表示可捕获所有类型的异常,一般会作为异常捕获的最后一个 except 块。
print("未知异常")
# try except 外的代码
print("程序继续运行")
运行结果:
请输入被除数:6
请输入除数:2
相除的商为: 3.0
程序继续运行
例二,触发异常
try:
# 可能出现异常的代码块
a = int(input("请输入被除数:"))
b = int(input("请输入除数:"))
c = a / b
print("相除的商为:", c)
except (ValueError, ArithmeticError): # ZeroDivisionError 是 ArithmeticError 的子类
# 处理异常的代码块
print("程序发生了数字格式异常、算术异常之一")
except : # 未指定具体要捕获的异常类型,这种省略异常类的 except 语句也是合法的,它表示可捕获所有类型的异常,一般会作为异常捕获的最后一个 except 块。
print("未知异常")
# try except 外的代码
print("程序继续运行")
运行结果:
请输入被除数:阿杰
程序发生了数字格式异常、算术异常之一
程序继续运行
例三,触发异常
try:
# 可能出现异常的代码块
a = int(input("请输入被除数:"))
b = int(input("请输入除数:"))
c = a / b
print("相除的商为:", c)
except (ValueError, ArithmeticError): # ZeroDivisionError 是 ArithmeticError 的子类
# 处理异常的代码块
print("程序发生了数字格式异常、算术异常之一")
except : # 未指定具体要捕获的异常类型,这种省略异常类的 except 语句也是合法的,它表示可捕获所有类型的异常,一般会作为异常捕获的最后一个 except 块。
print("未知异常")
# try except 外的代码
print("程序继续运行")
运行结果:
请输入被除数:6
请输入除数:0
程序发生了数字格式异常、算术异常之一
程序继续运行
1.2 获取异常信息的方式
(1)通过异常类提供的属性和方法获取异常信息
每种异常类型都提供了如下几个属性和方法,通过调用它们,就可以获取当前处理异常类型的相关信息:
args
:返回异常的错误编号和描述字符串;str(e)
:返回异常信息,但不包括异常信息的类型;repr(e)
:返回较全的异常信息,包括异常信息的类型。
举例如下所示:
在例二的基础上,添加获取异常信息的代码
try:
# 可能出现异常的代码块
a = int(input("请输入被除数:"))
b = int(input("请输入除数:"))
c = a / b
print("相除的商为:", c)
except (ValueError, ArithmeticError) as e: # ZeroDivisionError 是 ArithmeticError 的子类
# 处理异常的代码块
print("程序发生了数字格式异常、算术异常之一")
print('通过 e.args 获取异常信息为:', e.args)
print('通过 str(e) 获取异常信息为:', str(e))
print('通过 repr(e) 获取异常信息为:', repr(e))
except : # 未指定具体要捕获的异常类型,这种省略异常类的 except 语句也是合法的,它表示可捕获所有类型的异常,一般会作为异常捕获的最后一个 except 块。
print("未知异常")
# try except 外的代码
print("程序继续运行")
运行结果:
请输入被除数:阿杰
程序发生了数字格式异常、算术异常之一
通过 e.args 获取异常信息为: ("invalid literal for int() with base 10: '阿杰'",)
通过 str(e) 获取异常信息为: invalid literal for int() with base 10: '阿杰'
通过 repr(e) 获取异常信息为: ValueError("invalid literal for int() with base 10: '阿杰'")
程序继续运行
在例三的基础上,添加获取异常信息的代码
try:
# 可能出现异常的代码块
a = int(input("请输入被除数:"))
b = int(input("请输入除数:"))
c = a / b
print("相除的商为:", c)
except (ValueError, ArithmeticError) as e: # ZeroDivisionError 是 ArithmeticError 的子类
# 处理异常的代码块
print("程序发生了数字格式异常、算术异常之一")
print('通过 e.args 获取异常信息为:', e.args)
print('通过 str(e) 获取异常信息为:', str(e))
print('通过 repr(e) 获取异常信息为:', repr(e))
except : # 未指定具体要捕获的异常类型,这种省略异常类的 except 语句也是合法的,它表示可捕获所有类型的异常,一般会作为异常捕获的最后一个 except 块。
print("未知异常")
# try except 外的代码
print("程序继续运行")
运行结果:
请输入被除数:6
请输入除数:0
程序发生了数字格式异常、算术异常之一
通过 e.args 获取异常信息为: ('division by zero',)
通过 str(e) 获取异常信息为: division by zero
通过 repr(e) 获取异常信息为: ZeroDivisionError('division by zero')
程序继续运行
(2)使用 Python sys.exc_info() 方法获取异常信息
sys
模块中,有两个方法可以返回异常的全部信息,分别是 exc_info()
和 last_traceback()
,这两个函数有相同的功能和用法。
exc_info()
方法会将当前的异常信息以元组的形式返回,该元组中包含 3 个元素,分别为 type、value 和 traceback,它们的含义分别如下所示:
- type:异常类型的名称,它是 BaseException 的子类。
- value:捕获到的异常实例。
- traceback:是一个 traceback 对象。
举例如下所示:
import sys # 导入 sys 模块
def demo1(a, b):
c = a / b
print("相除的商为:", c)
def demo2(a, b):
demo1(a, b)
def demo3(a, b):
demo2(a, b)
try:
a = int(input("请输入被除数:"))
b = int(input("请输入除数:"))
demo3(a, b)
except: # 未指定具体要捕获的异常类型,这种省略异常类的 except 语句也是合法的,它表示可捕获所有类型的异常,一般会作为异常捕获的最后一个 except 块。
print(sys.exc_info())
运行结果:
请输入被除数:6
请输入除数:0
(<class 'ZeroDivisionError'>, ZeroDivisionError('division by zero'), <traceback object at 0x000002626F40CE00>)
无法直接看出有关异常的信息,还需要对 traceback 对象做进一步处理。
要查看 traceback 对象包含的内容,需要先引进 traceback 模块,然后调用 traceback 模块中的 print_tb() 方法,并将 sys.exc_info() 作为参数传入。
举例如下所示:
import sys # 导入 sys 模块
import traceback # 导入 traceback 模块
def demo1(a, b):
c = a / b
print("相除的商为:", c)
def demo2(a, b):
demo1(a, b)
def demo3(a, b):
demo2(a, b)
try:
a = int(input("请输入被除数:"))
b = int(input("请输入除数:"))
demo3(a, b)
except: # 未指定具体要捕获的异常类型,这种省略异常类的 except 语句也是合法的,它表示可捕获所有类型的异常,一般会作为异常捕获的最后一个 except 块。
print(sys.exc_info())
traceback.print_tb(sys.exc_info()[2]) # 进一步处理
运行结果:
请输入被除数:6
请输入除数:0
(<class 'ZeroDivisionError'>, ZeroDivisionError('division by zero'), <traceback object at 0x0000025DC895CB40>)
File "D:/Data/ProfessionalSkills/Python/PycharmProjects/demo/demo.py", line 33, in <module>
demo3(a, b)
File "D:/Data/ProfessionalSkills/Python/PycharmProjects/demo/demo.py", line 27, in demo3
demo2(a, b)
File "D:/Data/ProfessionalSkills/Python/PycharmProjects/demo/demo.py", line 23, in demo2
demo1(a, b)
File "D:/Data/ProfessionalSkills/Python/PycharmProjects/demo/demo.py", line 18, in demo1
c = a / b
(3)使用 Python traceback 模块获取异常信息
traceback
模块可以用来查看异常的传播轨迹,追踪异常触发的源头。
应用程序运行时,经常会发生一系列函数或方法调用。异常的传播则相反,只要异常没有被完全捕获(包括异常没有被捕获,或者异常被处理后重新引发了新异常),异常就从发生异常的函数或方法逐渐向外传播,首先传给该函数或方法的调用者,该函数或方法的调用者再传给其调用者,直至最后传到 Python 解释器,此时 Python 解释器会中止该程序,并打印异常的传播轨迹信息。
建议:从最后一行异常信息开始看,最后一行信息详细显示了异常的类型和异常的详细消息。从这一行向上,逐个记录了异常发生源头、异常依次传播所经过的轨迹,并标明异常发生在哪个文件、哪一行、哪个函数处。
使用 traceback 模块查看异常传播轨迹,首先需要将 traceback 模块引入,该模块提供了如下两个常用方法:
print_exc([limit[, file]])
:将异常传播轨迹信息输出到控制台或指定文件中。
(1)limit
:用于限制显示异常传播的层数,比如函数 A 调用函数 B,函数 B 发生了异常,如果指定 limit=1,则只显示函数 A 里面发生的异常。如果不设置 limit 参数,则默认全部显示。
(2)file
:指定将异常传播轨迹信息输出到指定文件中。如果不指定该参数,则默认输出到控制台。format_exc()
:将异常传播轨迹信息转换成字符串。和 print_exc() 效果是一样的。
举例如下所示:
例一,print_exc()
import traceback # 导入 traceback 模块
def demo1(a, b):
c = a / b
print("相除的商为:", c)
def demo2(a, b):
demo1(a, b)
def demo3(a, b):
demo2(a, b)
try:
a = int(input("请输入被除数:"))
b = int(input("请输入除数:"))
demo3(a, b)
except: # 未指定具体要捕获的异常类型,这种省略异常类的 except 语句也是合法的,它表示可捕获所有类型的异常,一般会作为异常捕获的最后一个 except 块。
traceback.print_exc()
运行结果:
请输入被除数:6
请输入除数:0
Traceback (most recent call last):
File "D:/Data/ProfessionalSkills/Python/PycharmProjects/demo/demo.py", line 30, in <module>
demo3(a, b)
File "D:/Data/ProfessionalSkills/Python/PycharmProjects/demo/demo.py", line 24, in demo3
demo2(a, b)
File "D:/Data/ProfessionalSkills/Python/PycharmProjects/demo/demo.py", line 20, in demo2
demo1(a, b)
File "D:/Data/ProfessionalSkills/Python/PycharmProjects/demo/demo.py", line 15, in demo1
c = a / b
ZeroDivisionError: division by zero
例二,format_exc()
import traceback # 导入 traceback 模块
def demo1(a, b):
c = a / b
print("相除的商为:", c)
def demo2(a, b):
demo1(a, b)
def demo3(a, b):
demo2(a, b)
try:
a = int(input("请输入被除数:"))
b = int(input("请输入除数:"))
demo3(a, b)
except: # 未指定具体要捕获的异常类型,这种省略异常类的 except 语句也是合法的,它表示可捕获所有类型的异常,一般会作为异常捕获的最后一个 except 块。
print(traceback.format_exc())
运行结果:
请输入被除数:6
请输入除数:0
Traceback (most recent call last):
File "D:/Data/ProfessionalSkills/Python/PycharmProjects/demo/demo.py", line 30, in <module>
demo3(a, b)
File "D:/Data/ProfessionalSkills/Python/PycharmProjects/demo/demo.py", line 24, in demo3
demo2(a, b)
File "D:/Data/ProfessionalSkills/Python/PycharmProjects/demo/demo.py", line 20, in demo2
demo1(a, b)
File "D:/Data/ProfessionalSkills/Python/PycharmProjects/demo/demo.py", line 15, in demo1
c = a / b
ZeroDivisionError: division by zero
2 try except else 详解
使用 else 包裹的代码,只有当 try 块没有捕获到任何异常时,才会得到执行;
如果 try 块捕获到异常,即便调用对应的 except 处理完异常,else 块中的代码也不会得到执行。
举例如下所示:
例一,else 块执行
import traceback
try:
res = 10 / int(input('请输入一个除数:'))
print(res)
except:
traceback.print_exc()
else:
print('else 块执行。')
运行结果:
请输入一个除数:2
5.0
else 块执行。
例二,else 块不执行
import traceback
try:
res = 10 / int(input('请输入一个除数:'))
print(res)
except:
traceback.print_exc()
else:
print('else 块执行。')
运行结果:
请输入一个除数:0
Traceback (most recent call last):
File "D:/Data/ProfessionalSkills/Python/PycharmProjects/demo/demo.py", line 3, in <module>
res = 10 / int(input('请输入一个除数:'))
ZeroDivisionError: division by zero
3 try except finally 详解
Python 异常处理机制还提供了一个 finally 语句,通常用来为 try 块中的程序做扫尾清理工作。例如,当 try 块中的程序打开了一些物理资源(文件、数据库连接等)时,由于这些资源必须手动回收,而回收工作通常就放在 finally 块中,这是一种比较好的选择。Python 垃圾回收机制,只能帮我们回收变量、类对象占用的内存,而无法自动完成类似关闭文件、数据库连接等这些的工作。
无论 try 块是否发生异常,最终都要进入 finally 语句,并执行其中的代码块。
注意:finally 语句和 else 语句不同,finally 只要求和 try 搭配使用,而至于该结构中是否包含 except 以及 else,对于 finally 不是必须的(else 必须和 try except 搭配使用)。
举例如下所示:
例一,没触发异常
import traceback
try:
res = 10 / int(input('请输入一个除数:'))
print(res)
except:
traceback.print_exc()
else:
print('else 块执行。')
finally:
print('finally 块执行。')
运行结果:
请输入一个除数:2
5.0
else 块执行。
finally 块执行。
例二,触发异常
import traceback
try:
res = 10 / int(input('请输入一个除数:'))
print(res)
except:
traceback.print_exc()
else:
print('else 块执行。')
finally:
print('finally 块执行。')
运行结果:
请输入一个除数:0
finally 块执行。
Traceback (most recent call last):
File "D:/Data/ProfessionalSkills/Python/PycharmProjects/demo/demo.py", line 3, in <module>
res = 10 / int(input('请输入一个除数:'))
ZeroDivisionError: division by zero
【友情链接】
微信公众号:码农阿杰
博客园
【参考资料】
Python 官网
Python 3.8.2 documentation
转载:https://blog.csdn.net/manongajie/article/details/106341680