写代码的时候可以手动抛出异常吗?答案是肯定的,Python 允许程序自己引发异常,只需使用 raise 语句即可。基本语法格式为:
raise [exceptionName [(reason)]]
其中,[]中包含的可选参数用于指定抛出异常的名称和异常信息的相关描述。如果省略所有可选参数, raise 将照原样抛出当前错误;如果只省略(reason),则抛出异常时不附加异常描述信息。
也就是说,raise 语句有如下三种常用的用法:
1. 加注:单次加注。此语句引发在当前上下文中捕获的异常(例如在 except 块中),或者默认情况下引发 RuntimeError 异常。
2.raise异常类名:raise后面跟一个异常类名。该语句抛出指定异常类的默认实例。
3、引发异常类名(描述信息):当引发指定异常时,附上异常的描述信息。
以上三种用法最终都是为了引发一个异常实例(即使指定了异常类,实际上也是该类的默认实例),而raise语句一次只能引发一个异常实例。
例如:
>>> raise
Traceback (most recent call last):
File "<pyshell#1>", line 1, in <module>
raise
RuntimeError: No active exception to reraise
>>> raise ZeroDivisionError
Traceback (most recent call last):
File "<pyshell#0>", line 1, in <module>
raise ZeroDivisionError
ZeroDivisionError
>>> raise ZeroDivisionError("除数不能为零")
Traceback (most recent call last):
File "<pyshell#2>", line 1, in <module>
raise ZeroDivisionError("除数不能为零")
ZeroDivisionError: 除数不能为零
请注意,即使是用户引发的异常也可以使用 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),这样函数的异常会直接导致程序中止。
运行上面程序,可以看到如下输出结果:
程序出现异常: 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 块捕获。
第二次调用mtd(3)导致的以“File”开头的三行输出实际上显示了异常传播轨迹信息。也就是说,如果程序不处理异常,Python会默认将异常传播轨迹信息输出到控制台。
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 语句来引发异常,raise 语句将重新引发 except 块捕获的异常。运行程序,可以看到如下输出:
转换出异常: could not convert string to float: 'df'
main 函数捕获的异常:<class 'ValueError'>
从输出中,main() 函数再次捕获 ValueError,这是 bid() 方法中的 except 块捕获的原始异常。
except 和 raise 同时使用
在实际应用中,异常可能需要更复杂的处理。当异常发生时,仅靠一个方法是无法完全处理异常的,必须多个方法配合才能完全处理异常。也就是说,在当前发生异常的方法中,程序只对异常进行了部分处理,有些处理需要在方法的调用者中完成,所以要再次引发异常,以便方法的调用者也能抓到它异常。
为了实现这种多个方法协同处理同一个异常的情况,可以结合一个异常块中的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异常,通知调用方再次处理AuctionException异常的方法。因此,程序中的main()函数,即bid()方法的调用者,也可以再次捕捉到AuctionException异常,并打印出该异常的详细描述。
这种 except 和 raise 的组合在实际应用中非常常见。实际应用中对异常的处理通常分为两部分:
应用后台需要通过日志记录异常的细节;
应用程序还需要根据异常向应用程序用户传达某种提示;
在这种情况下,所有的异常都需要两个方法来完成,这意味着except和raise必须一起使用。
如果程序需要直接传播原始异常的细节,Python也允许使用自定义异常来包装原始异常,只要将上面的代码①改成如下形式即可:
raise AuctionException(e)
以上就是将原始异常e包装成AuctionException异常,也称为异常包装或异常翻译。
自定义异常类
很多时候,程序选择引发自定义异常,因为异常的类名通常还包含有关异常的有用信息。所以当抛出异常时,应该选择合适的异常类,以便能清楚地描述异常。在这种情况下,应用程序通常需要引发自定义异常。
用户定义的异常应该继承自 Exception 基类或 Exception 的子类。自定义异常类的时候基本不用多写代码,只要指定自定义异常类的父类即可。
下面程序创建了一个自定义异常类:
class AuctionException(Exception):
pass
上面的程序创建了AuctionException异常类,它不需要类体定义,所以使用pass语句作为占位符。
在大多数情况下,创建自定义异常类可以使用与上述程序类似的代码,只需更改 AuctionException 异常的类名,使异常的类名能够准确描述异常。
python学习网,大量的免费
,欢迎在线学习!
本文为原创文章,版权归知行编程网所有,欢迎分享本文,转载请保留出处!
你可能也喜欢
- ♥ 如何检查python中的位数12/12
- ♥ 如何粘贴python程序12/09
- ♥ Python 操作带参数的装饰器12/31
- ♥ 如何在python中编写空函数?10/04
- ♥ 如何在python中从控制台输入08/13
- ♥ 如何在python中使用find函数08/12
内容反馈