Python 允许程序自行引发异常,自行引发异常使用 raise 语句来完成。

1.引发异常
raise 语句有如下三种常用的用法 :

  1. raise: 单独一个 raise。该语句引发当前上下文中捕获的异常(比如在 except块中),或默认引发 RuntimeError 异常 。
  2. raise 异常类: raise 后带一个异常类。该语句引发指定异常类的默认实例。
  3. raise 异常对象:引发指定的异常对象。

raise语句每次只能引发一个异常实例。

下面示范用户引发异常的两种方式:

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()

python 抛出详细的异常 python抛出异常raise_Python

上面第一行输出是第一次调用 mtd(3)的结果,该方法引发的异常被except 块捕获并处理。后面的一段输出的是第二次调用 mtd(3) 的结果,由于该异常没有被 except 块捕获,因此该异常一向上传播给 Python 解释器导致程序中止。

2.自定义异常类
很多时候程序可以选择引发自定义异常,因为异常的类名通常也包含了该异常的有用信息。所以在引发异常时,应该选择合适的异常类,从而可以明确的描述该异常情况。在这种情形下应用程序常常需要引发自定义异常。
用户自定义异常 应该继承 Exception 基类或Exception的子类,在字定义异常类时基本不需要书写更多的代码,只要指定自定义异常类的父类即可。

class AuctionException(Exception): pass

上面程序创建了AuctionException异常类,该异常类不需要类体定义,因此使用 pass 语句作为占位符即可。

3.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('竞拍价必须是数值,不能包含其他字符')
        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()

python 抛出详细的异常 python抛出异常raise_python 抛出详细的异常_02

except 块捕获到异常后,系统打印了该异常的字符串信息,接着引发一个 AuctionException 异常,通知该方法的调用者再次处理该 AuctionException 异常。所以 程序中的 main() 函数,也就是 bid()方法的调用者还可以再次捕获 AuctionException 异常,井将该异 常的详细描述信息打印出来。
实际应用对异常的处理通常分成 两个部分:①应用后台需要通过日志来记录异常发生的详细情况;②应用还需要根据异常向应用使用者传达某种提示。在这种情形下,所有异常都需要两个方法共同完成,也就必须将 except和raise 结合使用。
如果程序需要将原始异常的详细信息直接传播出去,Python 也允许用自定义异常对原始异常进行包装,只要将上面except块内的raise语句改为:

raise AuctionException(e)

上面就是把原始异常e包装成了AuctionException 异常,这种方式也被称为异常包装或异常转译。

4.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 Exception as ae:
        # 再次捕获到bid()方法中的异常,并对该异常进行处理
        print('main函数捕获的异常', ae)


main()

python 抛出详细的异常 python抛出异常raise_自定义异常_03