Python中raise语句的三种用法与自定义异常处理详解
本文详解Python中raise语句的三种用法:无参引发当前异常、带类名引发默认实例、带对象引发指定实例。通过五子棋与竞拍示例,演示如何结合try-except捕获用户引发的异常,以及如何通过except中再次raise实现多层级异常处理与日志记录,涵盖自定义异常类的创建与异常传播轨迹分析。
Python中raise语句的基本用法
当程序运行发生错误时,Python解释器会自动抛出异常。此外,开发者也可以主动在代码中触发异常,这一操作通过raise语句实现。
在许多业务场景中,是否抛出异常取决于具体的业务逻辑。如果程序中的数据状态或执行流程不符合预设的业务规则,这便构成了一种异常。这类因业务逻辑冲突而产生的异常无法由系统自动判断,必须由程序员根据实际需求手动触发。
若需在代码中主动抛出异常,应使用raise语句。raise语句主要有以下三种常用形式:
- 仅使用raise关键字:单独使用raise会抛出当前上下文中已捕获的异常(通常位于except块内);若不在异常处理块中,则默认抛出RuntimeError异常。
- raise后接异常类名:该形式会抛出指定异常类的默认实例。
- raise后接异常对象:直接抛出指定的异常实例。
上述三种形式最终都会导致一个异常实例被抛出(即使指定的是类,系统也会生成其默认实例)。需要注意的是,每次raise语句只能抛出一个异常实例。
主动抛出异常与异常处理机制
我们可以利用raise语句重构前文五子棋游戏中处理用户输入的逻辑:
try :
#将用户输入的字符串以逗号( ,)作为分隔符,分隔成两个字符串
x_str, y_str = inputStr.split(sep =",")
#如果要下棋的点不为空
if board[int(y_str) - 1] [int(x_str) - 1] != "+":
#引发默认的RuntimeError异常
raise
#把对应的列表元素赋为”●”
board [int(y_str) - 1] [int(x_str) - 1] = ”●”
except Exception as e:
print (type(e))
inputStr = input("您输入的坐标不合法,请重新输入,下棋坐标应以x,y 的格式\n")
continue
在示例代码的第7行,使用raise语句主动抛出异常。程序逻辑设定为:当用户试图在已有棋子的坐标落子时,即视为异常。当Python解释器接收到开发者主动抛出的异常时,会中止当前执行流,跳转至对应的except块进行处理。这表明,无论是系统自动抛出的异常还是程序员主动抛出的异常,Python解释器的处理机制完全一致。
即使是用户主动抛出的异常,也可以使用try-except结构进行捕获。当然,开发者也可以选择不捕获,让异常向调用栈上层(即调用者)传播。如果异常一直传播至Python解释器且未被处理,程序将会终止运行。
以下示例展示了处理用户主动抛出异常的两种不同方式:
def main():
try:
# 使用try...except来捕捉异常
# 此时即使程序出现异常,也不会传播给main函数
mtd(3)
except Exception as e:
print('程序出现异常:', e)
# 不使用try...except捕捉异常,异常会传播出来导致程序中止
mtd(3)
def mtd(a):
if a > 0:
raise ValueError("a的值大于0,不符合要求")
main()
从代码可见,程序既可以在调用mtd(3)时使用try-except捕获异常,这样异常会被except块处理,不会向上传播给调用函数;也可以直接调用mtd(3)而不使用try-except,此时异常会直接传播给调用函数。如果调用函数也不处理该异常,将导致程序终止。
运行上述程序,可观察到如下输出结果:
程序出现异常: a的值大于0,不符合要求 Traceback (most recent call last): File "C:\Users\mengma\Desktop\1.py", line 13, in <module> main() File "C:\Users\mengma\Desktop\1.py", line 9, in main mtd(3) File "C:\Users\mengma\Desktop\1.py", line 12, in mtd raise ValueError("a的值大于0,不符合要求") ValueError: a的值大于0,不符合要求
上述输出的第一行是第一次调用mtd(3)的结果,该异常被except块捕获并处理。后续的大段输出则是第二次调用mtd(3)的结果,由于未使用except块捕获,异常一直向上传播,最终传递给Python解释器导致程序终止。
第二次调用mtd(3)引发的以“File”开头的多行输出,实际上展示了异常的传播轨迹。也就是说,如果程序未对异常进行处理,Python默认会在控制台打印异常的传播路径信息。
自定义异常类的创建
自定义异常类
在许多情况下,程序可以选择抛出自定义异常,因为异常类的名称通常包含了该异常的有用信息。因此,在抛出异常时,应选择恰当的异常类,以明确描述异常发生的情况。在这种场景下,应用程序通常需要抛出自定义异常。
用户自定义的异常类必须继承自Exception基类或其子类。在创建自定义异常类时,通常无需编写大量代码,只需指定父类即可。
以下程序创建了一个自定义异常类(程序一):
class AuctionException(Exception): pass
上述代码创建了AuctionException异常类。由于该类无需定义具体的类体,因此使用pass语句作为占位符即可。
在大多数情况下,创建自定义异常类可采用与程序一相似的代码结构,只需将AuctionException替换为准确描述该异常的类名即可。
结合except与raise的多层异常处理
except和raise同时使用
在实际应用中,对异常的处理可能需要更复杂的逻辑。当某个异常出现时,单一方法可能无法完全处理,需要多个方法协作才能彻底解决。也就是说,在异常发生的当前方法中,程序仅对异常进行部分处理,其余处理逻辑需要在该方法的调用者中完成。因此,应再次抛出异常,使调用者也能捕获并处理该异常。
为了实现这种多方法协作处理同一异常的场景,可以在except块中结合raise语句。以下程序演示了except和raise结合使用的方法:
class AuctionException(Exception): pass
class AuctionTest:
def __init__(self, init_price):
self.init_price = init_price
def bid(self, bid_price):
d = 0.0
try:
d = float(bid_price)
except Exception as e:
# 此处只是简单地打印异常信息
print("转换出异常:", e)
# 再次引发自定义异常
raise AuctionException("竞拍价必须是数值,不能包含其他字符!") # ①
raise AuctionException(e)
if self.init_price > d:
raise AuctionException("竞拍价比起拍价低,不允许竞拍!")
initPrice = d
def main():
at = AuctionTest(20.4)
try:
at.bid("df")
except AuctionException as ae:
# 再次捕获到bid()方法中的异常,并对该异常进行处理
print('main函数捕捉的异常:', ae)
main()
在上述代码的第9至13行,except块捕获到异常后,首先打印该异常的字符串信息,接着抛出一个AuctionException异常,通知调用者再次处理该异常。因此,main()函数(即bid()方法的调用者)可以再次捕获AuctionException异常,并将异常的详细信息打印出来。
这种except和raise结合使用的情况在实际应用中非常普遍。对异常的处理通常分为两个部分:
应用后台需要通过日志记录异常发生的详细情况;
应用还需要根据异常向用户传达某种提示信息;
在这种情形下,所有异常都需要两个方法共同完成,因此必须将except和raise结合使用。
如果程序希望将原始异常的详细信息直接传播出去,Python也允许使用自定义异常对原始异常进行包装,只需将上述①号代码改为如下形式即可:
raise AuctionException(e)
raise不需要参数
正如前文所述,使用raise语句时可以不带参数。此时,若raise语句位于except块中,它将自动重新抛出当前上下文中激活的异常;否则,通常默认抛出RuntimeError异常。
例如,将上述程序修改为如下形式:
class AuctionException(Exception): pass
class AuctionTest:
def __init__(self, init_price):
self.init_price = init_price
def bid(self, bid_price):
d = 0.0
try:
d = float(bid_price)
except Exception as e:
# 此处只是简单地打印异常信息
print("转换出异常:", e)
# 再次引发自定义异常
raise
if self.init_price > d:
raise AuctionException("竞拍价比起拍价低,不允许竞拍!")
initPrice = d
def main():
at = AuctionTest(20.4)
try:
at.bid("df")
except AuctionException as ae:
# 再次捕获到bid()方法中的异常,并对该异常进行处理
print('main函数捕捉的异常:', ae)
main()
从第13行代码可见,此时程序在except块中仅使用raise语句抛出异常,该语句将重新抛出except块所捕获的异常。运行该程序,可观察到如下输出结果:
转换出异常: could not convert string to float: 'df'
main 函数捕获的异常:<class 'ValueError'>
raise语法补充与示例
知识点补充:
演示raise用法
try:
s = None
if s is None:
print "s 是空对象"
raise NameError #如果引发NameError异常,后面的代码将不能执行
print len(s) #这句不会执行,但是后面的except还是会走到
except TypeError:
print "空对象没有长度"
s = None
if s is None:
raise NameError
print 'is here?' #如果不使用try......except这种形式,那么直接抛出异常,不会执行到这里
触发异常
我们可以使用raise语句自己触发异常
raise语法格式如下:
raise [Exception [, args [, traceback]]]
语句中Exception是异常的类型(例如,NameError)参数标准异常中任一种,args是自已提供的异常参数。
最后一个参数是可选的(在实践中很少使用),如果存在,是跟踪异常对象。到此这篇关于Python新手学习raise用法的文章就介绍到这了,更多相关Python中raise用法内容请搜索本站以前的文章或继续浏览下面的相关文章希望大家以后多多支持本站!
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













