zoukankan      html  css  js  c++  java
  • Python raise用法(超级详细,看了无师自通)

    能否手动抛出一个异常吗?

    答案是肯定的,Python允许程序自行引发异常,使用 raise 语句即可。

    异常是一种很“主观”的说法,以下雨为例,假设大家约好明天去爬山郊游,如果第二天下雨了,这种情况会打破既定计划,就属于一种异常;但对于正在期盼天降甘霖的农民而言,如果第二天下雨了,他们正好随雨追肥,这就完全正常。

    很多时候,系统是否要引发异常,可能需要根据应用的业务需求来决定,如果程序中的数据、执行与既定的业务需求不符,这就是一种异常。由于与业务需求不符而产生的异常,必须由程序员来决定引发,系统无法引发这种异常。

    如果需要在程序中自行引发异常,则应使用 raise 语句,该语句的基本语法格式为:

    raise [exceptionName [(reason)]]

    其中,用 [] 括起来的为可选参数,其作用是指定抛出的异常名称,以及异常信息的相关描述。如果可选参数全部省略,则 raise 会把当前错误原样抛出;如果仅省略 (reason),则在抛出异常时,将不附带任何的异常描述信息。

    也就是说,raise 语句有如下三种常用的用法:

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

    上面三种用法最终都是要引发一个异常实例(即使指定的是异常类,实际上也是引发该类的默认实例),raise 语句每次只能引发一个异常实例。

    例如:

    >>> raise
    Traceback (most recent call last):
    File "<pyshell#1>", line 1, in
    raise
    RuntimeError: No active exception to reraise
    >>> raise ZeroDivisionError
    Traceback (most recent call last):
    File "<pyshell#0>", line 1, in
    raise ZeroDivisionError
    ZeroDivisionError
    >>> raise ZeroDivisionError("除数不能为零")
    Traceback (most recent call last):
    File "<pyshell#2>", line 1, in
    raise ZeroDivisionError("除数不能为零")
    ZeroDivisionError: 除数不能为零

    当然,我们手动让程序引发异常,很多时候并不是为了让其崩溃。事实上,raise 语句引发的异常通常用 try except(else finally)异常处理结构来捕获并进行处理。例如:

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

    程序运行结果为:

    输入一个数:a
    引发异常: ValueError('a 必须是数字',)

    可以看到,当用户输入的不是数字时,程序会进入 if 判断语句,并执行 raise 引发 ValueError 异常。但由于其位于 try 块中,因为 raise 抛出的异常会被 try 捕获,并由 except 块进行处理。

    因此,虽然程序中使用了 raise 语句引发异常,但程序的执行是正常的,手动抛出的异常并不会导致程序崩溃。

    raise 不需要参数

    正如前面所看到的,在使用 raise 语句时可以不带参数,例如:

    try:    
    	a = input("输入一个数:")    
    	if(not a.isdigit()):        
    		raise ValueError("a 必须是数字")
    except ValueError as e:    
    	print("引发异常:",repr(e))    
    	raise
    

    程序执行结果为:

    输入一个数:a
    引发异常: ValueError('a 必须是数字',)
    Traceback (most recent call last):
    File "D:python3.61.py", line 4, in
    raise ValueError("a 必须是数字")
    ValueError: a 必须是数字

    这里重点关注位于 except 块中的 raise,由于在其之前我们已经手动引发了 ValueError 异常,因此这里当再使用 raise 语句时,它会再次引发一次。

    当在没有引发过异常的程序使用无参的 raise 语句时,它默认引发的是 RuntimeError 异常。例如:

    try:    
    	a = input("输入一个数:")    
    	if(not a.isdigit()):        
    		raise 
    except RuntimeError as e:    
    	print("引发异常:",repr(e))
    

    程序执行结果为:

    输入一个数:a
    引发异常: RuntimeError('No active exception to reraise',)

    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 异常,通知该方法的调用者再次处理该 AuctionException 异常。所以程序中的 main() 函数,也就是 bid() 方法的调用者还可以再次捕获 AuctionException 异常,井将该异常的详细描述信息打印出来。

    这种 except 和 raise 结合使用的情况在实际应用中非常常用。实际应用对异常的处理通常分成两个部分:

    1. 应用后台需要通过日志来记录异常发生的详细情况;
    2. 应用还需要根据异常向应用使用者传达某种提示;

    在这种情形下,所有异常都需要两个方法共同完成,也就必须将 except 和 raise 结合使用。

    如果程序需要将原始异常的详细信息直接传播出去,Python 也允许用自定义异常对原始异常进行包装,只要将上面 ① 号代码改为如下形式即可:

    raise AuctionException(e)

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

    自定义异常类

    很多时候,程序可选择引发自定义异常,因为异常的类名通常也包含了该异常的有用信息。所以在引发异常时,应该选择合适的异常类,从而可以明确地描述该异常情况。在这种情形下,应用程序常常需要引发自定义异常。

    用户自定义异常都应该继承 Exception 基类或 Exception 的子类,在自定义异常类时基本不需要书写更多的代码,只要指定自定义异常类的父类即可。

    下面程序创建了一个自定义异常类:

    class AuctionException(Exception):
    pass

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

    在大部分情况下,创建自定义异常类都可采用与上面程序相似的代码来完成,只需改变 AuctionException 异常的类名即可,让该异常的类名可以准确地描述该异常。

    原文:http://c.biancheng.net/view/2360.html

  • 相关阅读:
    [dll注入实现IAT勾取] 计算器显示中文
    [记事本API Hook] 调试器 勾取 WriteFile()Api
    [DLL注入的方法]进程创建期修改PE输入表法
    [DLL注入的方法]静态修改PE输入表法
    [1]编程实现加载驱动
    [保护模式]测试一致代码段
    [保护模式]联系1 三环访问高2G
    15.[保护模式]TSS任务门
    ERP中HR模块的操作与设计--开源软件诞生26
    ERP的主数据的操作与设计--开源软件诞生25
  • 原文地址:https://www.cnblogs.com/remixnameless/p/13375086.html
Copyright © 2011-2022 走看看