zoukankan      html  css  js  c++  java
  • python笔记-异常处理

    一、异常

    即使语句或表达式在语法上是正确的,但在尝试执行时,它仍可能会引发错误。 在执行时检测到的错误被称为 异常,异常不一定会导致严重后果

    1.1 内置异常

    在 Python 中,所有异常必须为一个派生自 BaseException 的类的实例
    内置异常表

    BaseException             所有异常的基类         
     +-- SystemExit              解释器请求退出
     +-- KeyboardInterrupt          用户中断执行(通常是输入^C)
     +-- GeneratorExit            生成器(generator)发生异常来通知退出
     +-- Exception               常规错误的基类
          +-- StopIteration              迭代器没有更多值 
          +-- StopAsyncIteration              必须通过异步迭代器对象的__anext__()方法引发以停止迭代
          +-- ArithmeticError                 所有数值计算错误的基类
          |    +-- FloatingPointError             浮点计算错误
          |    +-- OverflowError                  数值运算超出最大限制
          |    +-- ZeroDivisionError              除(或取模)零 (所有数据类型
          +-- AssertionError                  断言语句失败
          +-- AttributeError                  对象没有这个属性
          +-- BufferError                    与缓冲区相关的操作时引发
          +-- EOFError                        没有内建输入,到达EOF 标记
          +-- ImportError                     导入失败
          |    +-- ModuleNotFoundError        找不到模块
          +-- LookupError                     无效数据查询的基类
          |    +-- IndexError                      序列中没有此索引(index)
          |    +-- KeyError                        映射中没有这个键
          +-- MemoryError                     内存溢出错误
          +-- NameError                       未声明、初始化对象
          |    +-- UnboundLocalError              访问未初始化的本地变量
          +-- OSError                         操作系统错误,
          |    +-- BlockingIOError               操作将阻塞对象设置为非阻塞操作
          |    +-- ChildProcessError             子进程上的操作失败
          |    +-- ConnectionError               与连接相关的异常的基类
          |    |    +-- BrokenPipeError             在已关闭写入的套接字上写入
          |    |    +-- ConnectionAbortedError      连接尝试被对等方中止
          |    |    +-- ConnectionRefusedError      连接尝试被对等方拒绝
          |    |    +-- ConnectionResetError        连接由对等方重置
          |    +-- FileExistsError               创建已存在的文件或目录
          |    +-- FileNotFoundError             请求不存在的文件或目录
          |    +-- InterruptedError              系统调用被输入信号中断
          |    +-- IsADirectoryError             在目录上请求文件操作
          |    +-- NotADirectoryError            在不是目录的事物上请求目录操作
          |    +-- PermissionError              在没有访问权限的情况下运行操作
          |    +-- ProcessLookupError            进程不存在
          |    +-- TimeoutError                  系统函数在系统级别超时
          +-- ReferenceError                弱引用试图访问已经垃圾回收了的对象
          +-- RuntimeError                  一般的运行时错误
          |    +-- NotImplementedError      尚未实现的方法
          |    +-- RecursionError           解释器检测到超出最大递归深度
          +-- SyntaxError                   Python 语法错误
          |    +-- IndentationError         缩进错误
          |         +-- TabError          Tab 和空格混用
          +-- SystemError              一般的解释器系统错误
          +-- TypeError               对类型无效的操作
          +-- ValueError              传入无效的参数
          |    +-- UnicodeError             Unicode 相关的错误
          |         +-- UnicodeDecodeError     Unicode 解码时的错误
          |         +-- UnicodeEncodeError     Unicode 编码时错误
          |         +-- UnicodeTranslateError  Unicode 转换时错误
          +-- Warning                       警告的基类
               +-- DeprecationWarning          关于被弃用的特征的警告
               +-- PendingDeprecationWarning   关于构造将来语义会有改变的警告
               +-- RuntimeWarning           可疑的运行行为的警告
               +-- SyntaxWarning            可疑的语法的警告
               +-- UserWarning              用户代码生成的警告
               +-- FutureWarning            有关已弃用功能的警告的基类
               +-- ImportWarning            模块导入时可能出错的警告的基类
               +-- UnicodeWarning           与Unicode相关的警告的基类
               +-- BytesWarning             bytes和bytearray相关的警告的基类
               +-- ResourceWarning           与资源使用相关的警告的基类
    

    二、处理异常

    可以编写处理所选异常的程序

    2.1 捕获一个异常

    try:
          x = int(input("Please enter a number: "))
    except ValueError:
          print("Oops!  That was no valid number.  Try again...")
    
    1. 首先,执行 try 子句 (tryexcept 关键字之间的(多行)语句)
    2. 如果没有异常发生,则跳过 except 子句 并完成 try 语句的执行
    3. 如果在执行 try 子句时发生了异常,则跳过该子句中剩下的部分。然后,如果异常的类型和 except 关键字后面的异常匹配,则执行 except 子句 ,然后继续执行 try 语句之后的代码
    4. 如果发生的异常和 except 子句中指定的异常不匹配,则将其传递到外部的 try 语句中;如果没有找到处理程序,则它是一个 未处理异常,执行将停止并显示如上所示的消息

    2.2 捕获多个异常

    try:
          x = int(input("Please enter a number: "))
    except (RuntimeError, TypeError, NameError, ValueError):
          pass
    
    1. 一个 try 语句可能有多个 except 子句,以指定不同异常的处理程序。 最多会执行一个处理程序。 处理程序只处理相应的 try 子句中发生的异常,而不处理同一 try 语句内其他处理程序中的异常。 一个 except 子句可以将多个异常命名为带括号的元组

    2.3 异常是捕获的同一个类或基类

    如果发生的异常和 except 子句中的类是同一个类或者是它的基类,则异常和 except 子句中的类是兼容的(但反过来则不成立 --- 列出派生类的 except 子句与基类不兼容)例如,下面的代码将依次打印 B, C, D

    class B(Exception):
        pass
    
    class C(B):
        pass
    
    class D(C):
        pass
    
    for cls in [B, C, D]:
        try:
            raise cls()
        except D:
            print("D")
        except C:
            print("C")
        except B:
            print("B")
    
    1. 请注意如果 except 子句被颠倒(把 except B 放到第一个),它将打印 B,B,B --- 即第一个匹配的 except 子句被触发。

    2.4 省略异常名

    最后except 子句可以省略异常名,以用作通配符。但请谨慎使用,因为以这种方式很容易掩盖真正的编程错误

    import sys
    
    try:
        f = open('myfile.txt')
        s = f.readline()
        i = int(s.strip())
    except OSError as err:
        print("OS error: {0}".format(err))
    except ValueError:
        print("Could not convert data to an integer.")
    except:
        print("Unexpected error:", sys.exc_info()[0])
        raise
    

    2.5 可选的else子句

    使用时必须放在所有的 except 子句后面。在try 子句不引发异常时必须执行的代码

    for arg in sys.argv[1:]:
        try:
            f = open(arg, 'r')
        except OSError:
            print('cannot open', arg)
        else:
            print(arg, 'has', len(f.readlines()), 'lines')
            f.close()
    
    1. 它避免了意外捕获由 try ... except 语句保护的代码未引发的异常。

    2.6 为异常参数

    except子句可以在异常名称后面指定一个变量。这个变量和一个异常实例绑定,它的参数存储在 instance.args 中。为了方便起见,异常实例定义了 __str__() ,因此可以直接打印参数而无需引用 .args 。也可以在抛出之前首先实例化异常,并根据需要向其添加任何属性

    try:
        raise Exception('spam', 'eggs')
    except Exception as inst:
        print(type(inst))    # the exception instance
        print(inst.args)     # arguments stored in .args
        print(inst)          # __str__ allows args to be printed directly,
                             # but may be overridden in exception subclasses
        x, y = inst.args     # unpack args
        print('x =', x)
        print('y =', y)
    

    输出:
    <class 'Exception'>
    ('spam', 'eggs')
    ('spam', 'eggs')
    x = spam
    y = eggs

    2.7 调用异常

    异常处理程序不仅处理 try 子句中遇到的异常,还处理 try 子句中调用(即使是间接地)的函数内部发生的异常

    >>> def this_fails():
    ...     x = 1/0
    ...
    >>> try:
    ...     this_fails()
    ... except ZeroDivisionError as err:
    ...     print('Handling run-time error:', err)
    ...
    Handling run-time error: division by zero
    

    三、抛出异常(raise)

    raise 语句允许程序员强制发生指定的异常

    raise NameError('HiThere')
    
    1. raise 唯一的参数就是要抛出的异常。这个参数必须是一个 异常实例 或者是一个 异常类(派生自 Exception 的类)。
    2. 如果传递的是一个异常类,它将通过调用没有参数的构造函数来隐式实例化

    四、用户自定义异常

    程序可以通过创建新的异常类来命名它们自己的异常。异常通常应该直接或间接地从 Exception 类派生。

    1. 可以定义异常类,它可以执行任何其他类可以执行的任何操作,但通常保持简单,通常只提供许多属性,这些属性允许处理程序为异常提取有关错误的信息。
    2. 在创建可能引发多个不同错误的模块时,通常的做法是为该模块定义的异常创建基类,并为不同错误条件创建特定异常类的子类
    class Error(Exception):
        """Base class for exceptions in this module."""
        pass
    
    class InputError(Error):
        """Exception raised for errors in the input.
    
        Attributes:
            expression -- input expression in which the error occurred
            message -- explanation of the error
        """
    
        def __init__(self, expression, message):
            self.expression = expression
            self.message = message
    
    class TransitionError(Error):
        """Raised when an operation attempts a state transition that's not
        allowed.
    
        Attributes:
            previous -- state at beginning of transition
            next -- attempted new state
            message -- explanation of why the specific transition is not allowed
        """
    
        def __init__(self, previous, next, message):
            self.previous = previous
            self.next = next
            self.message = message
    
    • 大多数异常都定义为名称以“Error”结尾,类似于标准异常的命名。
    • 许多标准模块定义了它们自己的异常,以报告它们定义的函数中可能出现的错误

    五、清理操作

    try 语句有另一个可选子句(finally),用于定义必须在所有情况下执行的清理操作

    1. 如果存在 finally 子句,则 finally 子句将作为 try 语句结束前的最后一项任务被执行
    2. finally 子句不论 try 语句是否产生了异常都会被执行
    >>> try:
    ...     raise KeyboardInterrupt
    ... finally:
    ...     print('Goodbye, world!')
    ...
    Goodbye, world!
    KeyboardInterrupt
    Traceback (most recent call last):
      File "<stdin>", line 2, in <module>
    

    发生异常finally执行情况

    1. 如果异常没有被某个 except 子句所处理,则该异常会在 finally 子句执行之后被重新引发
    2. 异常也可能在 exceptelse 子句执行期间发生。 同样地,该异常会在 finally 子句执行之后被重新引发。
    3. finally 子句将在执行 break, continuereturn 语句之前被执行
    4. 如果 finally 子句中包含一个 return 语句,则返回值将来自 finally 子句的某个 return 语句的返回值,而非来自 try 子句的 return 语句的返回值
  • 相关阅读:
    线程运行boost库在工作(22)任务之二
    vi 帮助文档 man vi
    跳槽关系三国演义告诉我们的60条真理
    后台端口虚拟主机wdcp的相关问题以及解决方法
    格式化字符串android 格式化时间
    对象查询HQL多表联合查询的问题
    myeclipse8.6中svn插件的安装
    乱码解决方法
    Restfull风格是什么意思?
    poj3013
  • 原文地址:https://www.cnblogs.com/duyupeng/p/13168145.html
Copyright © 2011-2022 走看看