zoukankan      html  css  js  c++  java
  • Python异常的处理记录

    参考资料来至:PythonCookbook

    首先要知道,所有的异常事一个类。

    如果一个单独的代码块处理所有不同的异常,可以将它们归组到一个元祖中。

    from urllib.error import URLError
    
    try:
        object.get_url(url)
    except (URLError, ValueError, SocketTimeout):
        object.remove_url(url)
    

     这个错误元祖(URLError, ValueError, SocketTimeout)捕获到都会执行object.remove_url(url)

    如果对一个单独的采取不同的处理方法,可以将其放入一个单独的except中

    try:
        object.get_url(url)
    except (URLError, ValueError):
        object.remove_url(url)
    except SocketTimeout:
        object.other_do(url)
    

    有许多归组为继承体系,对于这样的异常,可以通过指定一个基类来捕获所有异常。

    try:
        f = open('a.txt')
    except (FileNotFoundError, PermissionError):
        ...
    
    try:
        f = open('a.txt')
    except OSError:
        ...
    # 查下此类下面的子类
    print(OSError.__subclasses__())
    print()
    # 查看继承表 print(FileNotFoundError.__mro__)
    [<class 'ConnectionError'>, <class 'BlockingIOError'>, <class 'ChildProcessError'>, <class 'FileExistsError'>, 
    <class 'FileNotFoundError'>, <class 'IsADirectoryError'>, <class 'NotADirectoryError'>, <class 'InterruptedError'>,
    <class 'PermissionError'>, <class 'ProcessLookupError'>, <class 'TimeoutError'>, <class 'io.UnsupportedOperation'>, <class 'signal.ItimerError'>] (<class 'FileNotFoundError'>, <class 'OSError'>, <class 'Exception'>, <class 'BaseException'>, <class 'object'>)

     书中不严谨的地方事,明显OSError包含的错误类型更加多。

    我们还可以通过as e,这个e就是捕获到错误的实例,实例的话就应该有一堆属性,你也可以通过type(e)的方式查看e的类型,便于精准捕获。

    其中的error属性可以捕获到错误的代码。

    except向下执行捕获到合适的异常,下面的except就不会执行。

    try:
        f = open('a.txt')
    except OSError as e:
       print(dir(e)) print('OSError') # 这个肯定不会执行,应该OSError是FileNotFoundError的父类,它把包含它的所有异常都捕获了 except FileNotFoundError: print('FileNotFoundError')

    下面上一下OSError对象的属性

    ['__cause__', '__class__', '__context__', '__delattr__', '__dict__', 
    '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__',
    '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__ne__', '__new__',
    '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setstate__', '__sizeof__', '__str__',
    '__subclasshook__', '__suppress_context__', '__traceback__', 'args', 'characters_written', 'errno', 'filename', 'filename2', 'strerror', 'with_traceback']

    捕获所有的异常

    try:
        ...
    # 一般错误这个够用了
    except Exception as e:
        ...
    # 这个是错误的祖宗
    except BaseException as e:
        ...
    

     除了SystemExit,KeyboardInterrupt,和GeneratorExit之外,Exception都能捕获,如果想前面几个异常也捕获可以用BaseException。

    书中介绍说明,当我们捕获错误的时候,如果选择了Exception这样的广义错误,最好用as e,把e输出显示,这样再出现问题的时候,我们可以从实例e的输出中查看具体的情况。

    创建自定义的异常

    我们日常的使用中需要一些自己定义的异常,简单的操作,可以继承该类,并自己重新定义一个自己熟悉的类名。

    实际操作中,我们一般总继承内奸的Exception类,或者继承自一些本地定义的基类,而这个基类本身又是继承自Exception的,不能去继承BaseException。

    如果改写Exception的__init__方法,请确保所有参数传递给Exception的__init__,Exception默认的认为就是接收所有传递过来的参数,并将它以元祖的形式保存再args中。

    In [82]: class My_Exception(Exception): 
        ...:     def __init__(self,message, status): 
        ...:         super().__init__(message, status) 
        ...:         self.message = message 
        ...:         self.status = status 
        ...:                               
    In [85]: try: 
        ...:     raise My_Exception('my error','888') 
        ...: except My_Exception as e: 
        ...:     print(e.message) 
        ...:     print(e.status) 
        ...:     print(e.args) 
        ...:      
        ...:      
        ...:                                                                                                           
    my error
    888
    ('my error', '888')
    

    通过引发异常来响应另一个异常。

    要将异常串联起来,可以使用yield from。

    In [94]: def example(): 
        ...:     try: 
        ...:         int('n/a') 
        ...:     except ValueError as e: 
        ...:         raise RuntimeError('A parseing error occurred') from e 
        ...:                                                                                                           
    
    In [95]: example()                                                                                                 
    ---------------------------------------------------------------------------
    ValueError                                Traceback (most recent call last)
    <ipython-input-94-0e9d76aa20ee> in example()
          2     try:
    ----> 3         int('n/a')
          4     except ValueError as e:
    
    ValueError: invalid literal for int() with base 10: 'n/a'
    
    The above exception was the direct cause of the following exception:
    
    RuntimeError                              Traceback (most recent call last)
    <ipython-input-95-270ee176495d> in <module>
    ----> 1 example()
    
    <ipython-input-94-0e9d76aa20ee> in example()
          3         int('n/a')
          4     except ValueError as e:
    ----> 5         raise RuntimeError('A parseing error occurred') from e
          6 
    
    RuntimeError: A parseing error occurred
    
    In [96]:             
    

     这一行是关键The above exception was the direct cause of the following exception:

    在生成器throw(StopItoration)里面引起RuntimeError应该也是采用了yield from的方式。

    In [97]: try: 
        ...:     example() 
        ...: except RuntimeError as e: 
        ...:     print('It didnot work', e) 
        ...:     if e.__cause__: 
        ...:         print('Cause', e.__cause__,'type',type(e.__cause__)) 
        ...:          
        ...:                                                                                                           
    It didnot work A parseing error occurred
    Cause invalid literal for int() with base 10: 'n/a' type <class 'ValueError'>
    

     我们可以从捕获的RuntimeError对象e里面发现有__cause__属性,调用后,为引起它错误的实例。

    In [98]: def example(): 
        ...:     try: 
        ...:         int('n/a') 
        ...:     except ValueError: 
        ...:         raise RuntimeError('A parseing error occurred') 
        ...:          
        ...:                                                                                                           
    
    In [99]: try: 
        ...:     example() 
        ...: except RuntimeError as e: 
        ...:     print('It didnot work', e) 
        ...:     if e.__cause__: 
        ...:         print('Cause', e.__cause__,'type',type(e.__cause__)) 
        ...:          
        ...:                                                                                                           
    It didnot work A parseing error occurred
      
    In [100]: example()                                                                                                
    ---------------------------------------------------------------------------
    ValueError                                Traceback (most recent call last)
    <ipython-input-98-bdc7d22b895d> in example()
          2     try:
    ----> 3         int('n/a')
          4     except ValueError:

    ValueError: invalid literal for int() with base 10: 'n/a'

    During handling of the above exception, another exception occurred:

    RuntimeError                              Traceback (most recent call last)
    <ipython-input-100-270ee176495d> in <module>
    ----> 1 example()

    <ipython-input-98-bdc7d22b895d> in example()
          3         int('n/a')
          4     except ValueError:
    ----> 5         raise RuntimeError('A parseing error occurred')
          6
          7

    RuntimeError: A parseing error occurred

     上面去掉了yield from 可以发现两个错误没有因果关系,调用__cause__属性为空.

    在except里面无论是否是raise还是raise from,该脚本的调用者,抓取异常以最后复现的异常为准。就像前面写的函数,最后抓取函数异常,只能通过RuntimeError抓取。

    如果处于某种元婴想阻止异常链的发生,可以使用raise from None 完成

    In [103]: example()                                                                                                
    ---------------------------------------------------------------------------
    RuntimeError                              Traceback (most recent call last)
    <ipython-input-103-270ee176495d> in <module>
    ----> 1 example()
    
    <ipython-input-102-095e6117c755> in example()
          3         int('n/a')
          4     except ValueError:
    ----> 5         raise RuntimeError('A parseing error occurred') from None
          6 
          7 
    
    RuntimeError: A parseing error occurred
    

    在设计代码的时候,如果需要再except中raise 错误,经量应该使用raise from,这样能够明确的表达处你希望引发第二个异常的意图。

    少出现直接except下直接raise 下一个错误。

    重新抛出上一个异常

    我们在except块中捕获了一个异常,现在想将它重新抛出,可以再except中重新使用raise。

    In [106]: def example(): 
         ...:     try: 
         ...:         int('a') 
         ...:     except ValueError as e: 
         ...:         print(e) 
         ...:         raise 
         ...:                                                                                                          
    
    In [107]: example()                                                                                                
    invalid literal for int() with base 10: 'a'
    ---------------------------------------------------------------------------
    ValueError                                Traceback (most recent call last)
    <ipython-input-107-270ee176495d> in <module>
    ----> 1 example()
    
    <ipython-input-106-22d255d51f1f> in example()
          1 def example():
          2     try:
    ----> 3         int('a')
          4     except ValueError as e:
          5         print(e)
    
    ValueError: invalid literal for int() with base 10: 'a'
    

     这个以后再工作中,对异常进行采集还是非常有用的,采集了以后再次进行上浮报错。

  • 相关阅读:
    第六周总结&第四次实验报告
    课程总结
    第十四周课程总结&实验报告
    第十三周课程总结
    第十二周课程总结
    第十一周课程总结
    第十周课程总结
    第九周课程总结&实验报告(七)
    第八周课程总结&实验报告(六)
    第七周课程总结&实验报告(五)
  • 原文地址:https://www.cnblogs.com/sidianok/p/12229828.html
Copyright © 2011-2022 走看看