异常处理(一)try-except,try-except-else,try-except-finally,raise,sys.exe_info(),traceback

本文深入探讨Python的异常处理机制,包括try-except用于捕获错误,try-except-else在没有异常时执行特定代码,try-except-finally确保无论是否发生异常都会执行的清理代码,raise用于主动抛出异常,以及sys.exe_info()和traceback模块用于获取和打印详细的错误信息。通过这些工具,开发者可以更好地调试和控制程序的异常行为。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

异常类型含义
SyntaxError语法错误
AssertionErrorassert 后的条件为假时,程序停止运行抛出异常
AttributeError当试图访问的对象属性不存在时抛出的异常
IndexError索引超出序列范围会引发此异常
KeyError字典中查找一个不存在的关键字时引发此异常
NameError尝试访问一个未声明的变量时,引发此异常
TypeError不同类型数据之间的无效操作
ZeroDivisionError除法运算中除数为 0 引发此异常
IndentationErrorunexpected indents缩进异常
ValueError
ArithmeticErro
(1)try-except

try:
    可能产生异常的代码块
except [ (Error1, Error2, ... ) [as e] ]:
    处理异常的代码块1
except [ (Error3, Error4, ... ) [as e] ]:
    处理异常的代码块2
except  [Exception]:
    处理其它异常
  
1、捕获异常: 
	首先执行 try 中的代码块,如果执行过程中出现异常,自动生成一个异常类型,
	并将该异常提交给 Python 解释器
2、处理异常:	
	 Python 解释器收到异常对象时,寻找能处理该异常对象的 except 块,
	 如果找到合适的 except 块,则把该异常对象交给该 except 块处理
	 如果 Python 解释器找不到处理异常的 except 块,则程序运行终止,Python 解释器也退出

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

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

try:
    result = 20 / int(input('请输入除数:'))
    print(result)
except ValueError:
    print('必须输入整数')
except ArithmeticError:
    print('算术错误,除数不能为 0')
else:
    print('没有出现异常')
print("继续执行")

运行结果:
请输入除数:4
5.0
没有出现异常
继续执行

再次运行 运行结果:
请输入除数:a
必须输入整数
继续执行


try:
    result = 20 / int(input('请输入除数:'))
    print(result)
except ValueError:
    print('必须输入整数')
except ArithmeticError:
    print('算术错误,除数不能为 0')
print('没有出现异常')
print("继续执行")

运行结果:
请输入除数:a
必须输入整数
没有出现异常
继续执行

3try-except-finally
无论 try 块是否发生异常,最终都要进入 finally 语句并执行其中的代码块
即便当 try 块发生异常且没有合适和 except 处理异常时,finally 块中的代码也会执行

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

当 try 块中的程序打开了一些物理资源(文件、数据库连接等)时
由于这些资源必须手动回收,而回收工作通常就放在 finally 块中
注意:
Python 垃圾回收机制,只能帮我们回收变量、类对象占用的内存
而无法自动完成类似关闭文件、数据库连接等这些的工作。

但是回收这些物理资源,也不是必须使用 finally ,但使用 finally 块是比较好的选择
因为:
首先,try 块不适合做资源回收,因为一旦 try 块中的某行代码发生异常,其后续代码将不会执行
其次,exceptelse 也不适合,它们都可能不会得到执行
而 finally 块中的代码,无论 try 块是否发生异常,finally 块中的代码也会执行


try:
    a = int(input("请输入 a 的值:"))
    print(20/a)
except:
    print("发生异常!")
else:
    print("无错执行 else 块中的代码")   
finally :
    print("执行 finally 块中的代码")

请输入 a 的值:4
5.0
无错执行 else 块中的代码
执行 finally 块中的代码


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


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
    
(4)获取特定异常的有关信息
每种异常类型都提供了如下几个属性和方法,通过调用它们,就可以获取当前处理异常类型的相关信息:
args:返回异常的错误编号和描述字符串;
str(e):返回异常信息,但不包括异常信息的类型;
repr(e):返回较全的异常信息,包括异常信息的类型。

后面还可以了解到可以通过 traceback 模块获取异常信息


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可以处理多种异常
5raise 在程序的指定位置手动抛出一个异常 手动抛出的异常并不会导致程序崩溃

基本语法格式为:
raise [exceptionName [(reason)]]
raise:单独一个 raise。
	引发当前上下文中捕获的异常(比如在 except 块中)或默认引发 RuntimeError 异常。
raise 异常类名称:raise 后带一个异常类名称,表示引发执行类型的异常。
raise 异常类名称(描述信息):在引发指定类型的异常的同时,附带异常的描述信息。


try:
    a = input("输入一个数:")
    #判断用户输入的是否为数字
    if(not a.isdigit()):
        raise ValueError("a 必须是数字")
except ValueError as e:
    print("引发异常:",repr(e))
    
程序运行结果为:
输入一个数:a
引发异常: ValueError('a 必须是数字',)

tryraise抛出ValueError异常,被try捕获,在except中处理该异常



当在没有引发过异常的程序使用无参的 raise 语句时,它默认引发的是 RuntimeError 异常。例如:
try:
    a = input("输入一个数:")
    if(not a.isdigit()):
        raise
except RuntimeError as e:
    print("引发异常:",repr(e))
程序执行结果为:
输入一个数:a
引发异常: RuntimeError('No active exception to reraise',)
6)有时只获得异常的类型是远远不够的,还需要借助更详细的异常信息才能解决问题
捕获异常时,有 2 种方式可获得更多的异常信息,分别是:
1、使用 sys 模块中的 exc_info 方法;
	将当前的异常信息以元组的形式返回,该元组中包含 3 个元素:
		type:异常类型的名称,它是 BaseException 的子类
		value:捕获到的异常实例
		traceback:是一个 traceback 对象
		
	对于第 3 个元素traceback 对象,无法直接看出有关异常的信息,还需要对其做进一步处理
	要查看 traceback 对象包含的内容需要
		调用 traceback 模块的 print_tb 方法
		并将 sys.exc_info() 输出的 traceback 对象作为参数参入:
		traceback.print_tb(sys.exc_info()[2])
		
2、使用 traceback 模块 查看异常的传播轨迹,追踪异常触发的源头,参见本文最后的详细介绍

注意:
使用 sys、traceback 模块之前,都需要 import 引入



import sys
try:
    x = int(input("请输入一个被除数:"))
    print("30除以",x,"等于",30/x)
except:
    print(sys.exc_info())
    print("其他异常...")

当输入 0 时,程序运行结果为:
请输入一个被除数:0
(<class 'ZeroDivisionError'>, 
ZeroDivisionError('division by zero',), 
<traceback object at 0x000001FCF638DD48>)
其他异常...
#使用 sys 模块之前,需使用 import 引入
import sys
#引入traceback模块
import traceback
try:
    x = int(input("请输入一个被除数:"))
    print("30除以",x,"等于",30/x)
except:
    #print(sys.exc_info())
    traceback.print_tb(sys.exc_info()[2])
    print("其他异常...")


输入 0,程序运行结果为:
请输入一个被除数:0
  File "C:\Users\mengma\Desktop\demo.py", line 7, in <module>
    print("30除以",x,"等于",30/x)
其他异常...


输出信息中包含了更多的异常信息,包括文件名、抛出异常的代码所在的行数、抛出异常的具体代码。
(7)traceback 查看异常的传播轨迹,追踪异常触发的源头。

class SelfException(Exception):
    pass
def main():
    firstMethod()
def firstMethod():
    secondMethod()
def secondMethod():
    thirdMethod()
def thirdMethod():
    raise SelfException("自定义异常信息")
main()

运行结果
Traceback (most recent call last):
  File "C:\Users\mengma\Desktop\1.py", line 11, in <module>
    main()
  File "C:\Users\mengma\Desktop\1.py", line 4, in main            <--mian函数
    firstMethod()
  File "C:\Users\mengma\Desktop\1.py", line 6, in firstMethod     <--第三个
    secondMethod()
  File "C:\Users\mengma\Desktop\1.py", line 8, in secondMethod    <--第二个
    thirdMethod()
  File "C:\Users\mengma\Desktop\1.py", line 10, in thirdMethod    <--异常源头
    raise SelfException("自定义异常信息")
SelfException: 自定义异常信息

会标明异常发生在哪个文件、哪一行、哪个函数处

异常的传播顺序与函数调用顺序相反,只要异常没有被完全捕获(包括异常没有被捕获,
或者异常被处理后重新引发了新异常),异常就从发生异常的函数或方法逐渐向外传播,
首先传给该函数或方法的调用者,该函数或方法的调用者再传给其调用者,
直至最后传到 Python 解释器,此时 Python 解释器会中止该程序,并打印异常的传播轨迹信息。




# 导入trackback模块
import traceback
class SelfException(Exception): pass
def main():
    firstMethod()
def firstMethod():
    secondMethod()
def secondMethod():
    thirdMethod()
def thirdMethod():
    raise SelfException("自定义异常信息")
try:
    main()
except:
    # 捕捉异常,并将异常传播信息输出控制台
    traceback.print_exc()
    # 捕捉异常,并将异常传播信息输出指定文件中
    traceback.print_exc(file=open('log.txt', 'a'))


traceback模块常用函数:
traceback.print_exc():将异常传播轨迹信息输出到控制台或指定文件中。
format_exc():将异常传播轨迹信息转换成字符串。

语法格式:print_exc([limit[, file]]) 
limit:用于限制显示异常传播的层数,比如函数 A 调用函数 B,函数 B 发生了异常,
如果指定 limit=1,则只显示函数 A 里面发生的异常。如果不设置 limit 参数,则默认全部显示。
file:指定将异常传播轨迹信息输出到指定文件中。如果不指定该参数,则默认输出到控制台。
# -*- coding=utf-8 -*- import matplotlib.pyplot as plt import pydicom import pydicom.uid import sys import PIL.Image as Image # from PyQt5 import QtGui import os have_numpy = True try: import numpy except ImportError: have_numpy = False raise sys_is_little_endian = (sys.byteorder == 'little') NumpySupportedTransferSyntaxes = [ pydicom.uid.ExplicitVRLittleEndian, pydicom.uid.ImplicitVRLittleEndian, pydicom.uid.DeflatedExplicitVRLittleEndian, pydicom.uid.ExplicitVRBigEndian, ] # 支持的传输语法 def supports_transfer_syntax(dicom_dataset): """ Returns ------- bool True if this pixel data handler might support this transfer syntax. False to prevent any attempt to try to use this handler to decode the given transfer syntax """ return (dicom_dataset.file_meta.TransferSyntaxUID in NumpySupportedTransferSyntaxes) def needs_to_convert_to_RGB(dicom_dataset): return False def should_change_PhotometricInterpretation_to_RGB(dicom_dataset): return False # 加载Dicom图像数据 def get_pixeldata(dicom_dataset): """If NumPy is available, return an ndarray of the Pixel Data. Raises ------ TypeError If there is no Pixel Data or not a supported data type. ImportError If NumPy isn't found NotImplementedError if the transfer syntax is not supported AttributeError if the decoded amount of data does not match the expected amount Returns ------- numpy.ndarray The contents of the Pixel Data element (7FE0,0010) as an ndarray. """ if (dicom_dataset.file_meta.TransferSyntaxUID not in NumpySupportedTransferSyntaxes): raise NotImplementedError("Pixel Data is compressed in a " "format pydicom does not yet handle. " "Cannot return array. Pydicom might " "be able to convert the pixel data " 帮
最新发布
03-29
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值