zoukankan      html  css  js  c++  java
  • Python学习笔记-异常处理

    异常处理

    Python Errors and Exceptions 官方文档

    • 引发异常:

      • 语法: 使用raise 关键字, raise either an exception instance or an exception class (a class that derives from Exception).
        raise NameError('wrong name')
        样例输出:
         File "<stdin>", line 1, in <module>
         NameError: wrong name
      
      • 常见的内置异常类:
        • Exception:
        • AttributeError: 引用属性或给它赋值失败
        • IndexError: 使用了序列中不存在的索引时引发, 为Lookup Error子类
        • KeyError: 使用映射中不存在的索引时引发, 为Lookup Error子类
        • NameError: 找不到对应名称(变量)时引发
        • TypeError: 将内置操作或函数用于类型不正确的对象时引发
        • ValueError: 将内置操作或函数用于这样的对象时引发, 类型正确但是包含的值不对
    • 创建异常(User-defined Exception):

      • 语法: 创建一个异常类, 必须要保证直接或间接的继承Exception父类 Exceptions should typically be derived from the Exception class, either directly or indirectly.
      • 样例: class MyError(Exception): pass
      • 细节:
        • 类尽量简单, 只需要定义一些关于Error的属性, 方便传给handler进行异常处理
        • 如果在一个module当中需要定义多个Exception Class, 先定义一个BaseError Class, 让其他的subclass Error来继承该BaseError Class: When creating a module that can raise several distinct errors, a common practice is to create a base class for exceptions defined by that module, and subclass that to create specific exception classes for different error conditions:
        • 异常的定义应当以'Error'结尾,这样符合内置异常的命名规范
    • 处理异常

      • 语法: try/except 关键字

      • 样例: try 后面可以接 0个 exception, 1个 exception, 多个exception

        • 0个exception(危险的操作,尽量避免) 表示一次打包处理所有的异常
        • 1个异常: 只有异常名称对应于try当中抛出的异常时才会被执行
        • 多个异常:
          • 样例: exception (NameError, TrancisionError, ValueError): pass 三个当中任意一个满足时,都会catch并处理
          • 细节: 语法当中的( )不能省略, except RuntimeError, TypeError is not equivalent to except (RuntimeError, TypeError): but to except RuntimeError as TypeError
      • try关键字的执行流程:
        The try statement works as follows.
        First, the try clause (the statement(s) between the try and except keywords) is executed.
        If no exception occurs, the except clause is skipped and execution of the try statement is finished.
        If an exception occurs during the execution of the try clause, the rest of the clause is skipped. Then if its type matches the exception named after the except keyword, the except clause is executed, and then execution continues after the try statement.
        If an exception occurs which does not match the exception named in the except clause, it is passed on to outer try statements; if no handler is found, it is an unhandled exception and execution stops with a message as shown above.

      • 对except子句当中访问异常对象本身的操作:

        • 为exception instance 命名, 以便于在异常的内部进行调用
        • 为异常对象添加attribute: we can add arguments to the exception. The except clause may specify a variable after the exception name (or tuple). The variable is bound to an exception instance with the arguments stored in instance.args. 必须要对instance命名, 然后才能在之后面进行调用
      • 异常当中的else语句: 执行没有异常时需要做的事情
        The try … except statement has an optional else clause, which, when present, must follow all except clauses. It is useful for code that must be executed if the try clause does not raise an exception. For example:

    try:
        <statements>  # Run this main action first
    except <name1>:
        <exc1>           # 当 try中发生了 name1 的异常时运行exc1
    except <name2>:
        <exc2>           # 当 try中发生了 name2 的异常时运行exc2
    except (<name3>, <name4>:
        <exc3>           # 当 try中发生了 name3 OR name4 的异常时运行exc3
    else: 
        <exc4>           # 当代码没有异常时运行exc4
    finally: 
        <final>            #不管代码有没有异常都会执行final, 通常用来做一些清理工作
    
    • 细节: 异常处理当中的几点基本原则:
      • 注意异常的粒度,try当中不应当放入过多的代码,过多的代码会使得异常的定位难以定位, 尽量只在可能抛出异常的语句块前面放入try语句
      • 谨慎使用单独的except语句处理所有异常, 最好能够定位具体的异常。因为不加具体类型的except可能会掩盖真实的错误
      • 样例:
      import sys
      try: 
          print a
          b = 0
          print a / b
      except:
          sys.exit("ZeroDivisionError:Can not division zero")
      
      程序打印"ZeroDivisionError: Can not division zero", 但是这不是真正的错误原因, 真正的错误原因是a 在使用之前没有进行定义
      • 注意异常的捕获顺序: 小 -> 大 因为异常的捕获是顺序执行的, 小的在前可以直接精确定位异常, 而大的在前如果锁定不了异常的话, 还要再次执行小的,多此一举,大小的划分根据内建异常的继承结构来确定。原则是如果异常能够在被捕获的位置处理就应当及时的进行处理, 不能处理也应当以合适的方式向上层抛出。向上层传递时使用raise关键字即可。大类错误可以捕捉子类中的错误

    【25/91建议】避免finally 可能发生的陷阱:

    • 陷阱: 异常屏蔽 OR 设计好的return语句被屏蔽
      • 当finally 语句之中出现了returnbreak语句时, 临时保存的异常 和 try当中原本被设计好的return语句将被丢失
      • 样例:
      def ReturnTest(a):
          try:
              if a <= 0:
                  raise ValueError("data can not be negative")
              else:
                  return a
          except ValueError as e:
              print e
          finally:
              print("The End!")
              return -1
      
          print ReturnTest(0) # 输出"The End!" "-1" 
          print ReturnTest(1) # 输出"The End!" "-1"  出现问题
      

    finally 当中的return在try 中的else 语句之前执行, 所以会直接运行 finally 当中的return -1 而不是try 当中的 return a

    • 异常处理模板:

      • try/finally结构: 如果既要将异常向上传播, 又要在异常发生时进行清理工作
      • 样例: read方法抛出的异常会向上传播给调用方, 而finally代码块中的handle.close方法则一定能被执行。open方法必须放在try语句外, 这样如果打开文件时发生异常会跳过finally块
      handle = open('/tmp/random_data.txt') # May raise IOError
      try:
          data = handle.read() # May raise UnicodeDecode Error
      finally:
          handle.close() # Always runs after try
      
      • try/except/else结构: 清晰描述哪些异常由自己的代码处理、哪些异常会传给上一级。如果try代码中没有发生异常, 那么就执行else语句, 有了这种else 语句, 我们就可以尽量缩减try中的代码量。
      • 样例:
      def load_json_key(data, key):
          try:
              result_dict = json.loads(data) # 尝试读取一个JSON文件
          except ValueError as e:
              raise KeyError from e  # 如果代码不是有效的JSON格式, 会产生ValueError
          else:
              return result_dict[key] # 代码是有效的JSOn格式, 进行处理
      
      • 全套四合一 try/except/else/finally结构
      • 样例:
      def divide_json(path):
      handle = open(path, 'r+')
      try:
          data = handle.read()
          op = json.loads(data)
          value = (
              op['numerator'] /
              op['denominator']) # May raise ZeroDivisionError
      except ZeroDivisionError as e:
          return UNDEFINED
      else:
          op['result'] = value
          result = json.dumps(op)
          handle.seek(0)
          handle.write(result) # May raise IOError
          return value
      finally:
          handle.close() # Always runs
      
    • 使用内置的logging模块 来记录exception信息

    • 样例:

    def main():
        try:
            bar('0')
        except Exception as e:
            logging.exception(e)
    
  • 相关阅读:
    [洛谷P1155] 双栈排序
    [洛谷P4315] 月下”毛景“树
    [洛谷P2486] [SDOI2011]染色
    [HNOI2010] 弾飞绵羊
    mysql注入总结
    cisco交换机实现端口聚合
    python为运维人员打造一个监控脚本
    复习ACCESS注入
    利用sfc文件构建网络渗透
    FTP站点设置
  • 原文地址:https://www.cnblogs.com/kong-xy/p/10225071.html
Copyright © 2011-2022 走看看