• 语言基础篇12——Python有哪些异常,优雅的处理异常


    异常

    try-except[*]-else-finally

    执行顺序与返回值

    i的类型不同外,其余逻辑均相同,比较i作为整型和i作为列表的两种情况下的返回值,i为整型时,后两次返回值不一样,i为列表时,后两次返回值异常。此处利用不可变类型和可变类型的特点可反映出try-except时返回值如何处理的,执行return先记录返回值地址,然后走完后续try-except流程,返回这个地址中的对象。

    i为整型,初始值1,分别返回1、2、3

    def return_int(x):
        try:
            i = 1
            if x == 1:
                return i
        except Exception as error:
            print(error)
        else:
            i += 1
            print("无异常执行else")
            if x == 2:
                return i
        finally:
            i += 1
            print("不管代码是否有问题均执行finally")
            if x == 3:
                return i
    
    
    # 正常 try -> else -> finally
    # 异常 try -> except -> finally
    
    
    # try返回值 x == 1
    print("→", return_int(1))
    # 不管代码是否有问题均执行finally
    # → 1
    
    # else返回值 x == 2
    print("→", return_int(2))
    # 无异常执行else
    # 不管代码是否有问题均执行finally
    # → 2
    
    
    # finally返回值 x == 3
    print("→", return_int(3))
    # 无异常执行else
    # 不管代码是否有问题均执行finally
    # → 3
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    i为列表,初始值为[1],分别返回[1, 3]、[1, 2, 3]、[1, 2, 3]

    def return_int(x):
        try:
            i = [1]
            if x == 1:
                return i
        except Exception as error:
            print(error)
        else:
            i.append(2)
            print("无异常执行else")
            if x == 2:
                return i
        finally:
            i.append(3)
            print("不管代码是否有问题均执行finally")
            if x == 3:
                return i
    
    # 正常 try -> else -> finally
    # 异常 try -> except -> finally
    
    
    # try返回值 x == 1
    print("→", return_int(1))
    # 不管代码是否有问题均执行finally
    # → [1, 3]
    
    # else返回值 x == 2
    print("→", return_int(2))
    # 无异常执行else
    # 不管代码是否有问题均执行finally
    # → [1, 2, 3]
    
    
    # finally返回值 x == 3
    print("→", return_int(3))
    # 无异常执行else
    # 不管代码是否有问题均执行finally
    # → [1, 2, 3]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    单异常处理

    except处理异常组也只处理一次,异常组本质上也是一种异常

    import builtins  # 手动导入也没问题
    
    
    def division(a, b, c, d, f, g):
        try:
            type([1, 2, 3][a])
            if b:
                raise UserWarning('UserWarning')
            c / d
            if f:
                eval("hia hia hia")
            if g:
                raise ExceptionGroup("group", [KeyError(), ValueError(), ExceptionGroup("sub_group", [OSError()])])
        except IndexError:
            print("IndexError")
        except (Warning, ArithmeticError) as e:
            print(e, type(e))
        except ExceptionGroup as e:
            print(e, type(e))
        except Exception as e:
            print('exception兜底', e, type(e))  # 应当在所有异常之后,用于异常捕获兜底
        else:
            print("无异常执行else")
        finally:
            print("不管代码是否有问题均执行finally")
    
    
    print(division(0, False, 1, 1, False, builtins.str()))
    # 无异常执行else
    # 不管代码是否有问题均执行finally
    # None
    
    
    print(division(520, False, 1, 1, 0, builtins.str()))
    # IndexError
    # 不管代码是否有问题均执行finally
    # None
    
    
    print(division(0, True, 1, 1, 0, builtins.str()))
    # UserWarning 
    # 不管代码是否有问题均执行finally
    # None
    
    
    print(division(0, False, 1, 0, 0, builtins.str()))
    # division by zero 
    # 不管代码是否有问题均执行finally
    # None
    # 基于父类捕获异常 ArithmeticError是的父类ZeroDivisionError
    
    
    print(division(0, False, 1, 1, 1, builtins.str()))
    # exception兜底 invalid syntax (, line 1) 
    # 不管代码是否有问题均执行finally
    # None
    # 通常使用Exception兜底,Exception为异常体系中大多数异常的父类
    
    print(division(0, False, 1, 1, 0, builtins.str("-")))
    # group (3 sub-exceptions) 
    # 不管代码是否有问题均执行finally
    # 三个子异常
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62

    异常组处理

    Python3.11.4及以后引入异常组及except*语句,except*处理异常组会对异常组中每一个异常匹配一次

    def division(a, b=1):
        try:
            match a / b:
                case 1:
                    raise ZeroDivisionError()
                case 2:
                    raise ExceptionGroup('error', [ValueError('value error'), TypeError('type error')])
                case 3:
                    raise ExceptionGroup('error',
                                         [ZeroDivisionError(), ExceptionGroup('param error', [ValueError('value error'),
                                                                                              TypeError('type error')])])
                case 4:
                    raise ExceptionGroup('error', [ZeroDivisionError()])
                case 5:
                    raise ZeroDivisionError
                case 6:
                    raise ExceptionGroup('error', [ZeroDivisionError])
                case 7:
                    raise ExceptionGroup('error',
                                         [ZeroDivisionError, ExceptionGroup('param error', [ValueError('value error')])])
                case 8:
                    raise ExceptionGroup('error', [ZeroDivisionError, KeyError(), ValueError])
        except* ArithmeticError as e:  # ZeroDivisionError的父类
            print(1, e, type(e))
        except* ValueError as e:
            print(2, e, type(e))
        except* KeyError as e:
            print(3, e, type(e))
        except* Exception as e:
            print(4, e, type(e))
        finally:
            print("""↑↑↑""")
    
    
    # except和except*不兼容
    # SyntaxError: cannot have both 'except' and 'except*' on the same 'try'
    division(1)
    #  1  (1 sub-exception) 
    # 单个异常会被以异常组的方式捕获
    
    division(2)
    # 2 error (1 sub-exception) 
    # 4 error (1 sub-exception) 
    # 异常组中每个单个异常会被捕获一次
    
    division(3)
    # 1 error (1 sub-exception) 
    # 2 error (1 sub-exception) 
    # 4 error (1 sub-exception) 
    # 异常组可以嵌套为树状
    
    division(4)
    # 1 error (1 sub-exception) 
    
    division(5)
    # 1  (1 sub-exception) 
    # ZeroDivisionError不带()可以被捕获
    
    division(6)
    # 2  (1 sub-exception) 
    # 但在异常组中不带()会报异常 ValueError: Item 0 of second argument (exceptions) is not an exception
    # 没有匹配到 ArithmeticError
    
    
    division(7)
    # 2  (1 sub-exception) 
    # # 但在异常组中不带()会报异常
    
    division(8)
    # 2  (1 sub-exception) 
    # # 但在异常组中不带()会报异常
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71

    返回值机制

    def division(x):
        try:
    
            i = 1
            if x == 1:
                return i
            if x == 3:
                raise ZeroDivisionError()
        except Exception as error:
            print(error)
            i = 0
            return i
        else:
            i = 2
            print("无异常执行else")
            return i
        finally:
            i = 3
            print("不管代码是否有问题均执行finally")
            if x == 4:
                return i
    
    
    # 正常执行
    print("→", division(1))
    # 不管代码是否有问题均执行finally
    # → 1
    
    print("→", division(2))
    # 无异常执行else
    # 不管代码是否有问题均执行finally
    # → 2
    # 重点看这个i的变化和输出值
    
    print("→", division(3))
    #
    # 不管代码是否有问题均执行finally
    # → 0
    
    print("→", division(4))
    # 无异常执行else
    # 不管代码是否有问题均执行finally
    # → 3
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    注:

    1. try-except各个子块下变量在同一个命名空间

      # 报错
      i = 0
      def func():
          i += 2
          print(i)
      func()
      
      # 不报错
      try:
          i = 0
      except Exception():
          ...
      else:
          i += 1
      finally:
          i += 1
      print(i)
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17

    内置异常层次结构

    exception-hierarchy,内置异常即builtins中的异常

    BaseException                              异常基类
     ├── BaseExceptionGroup                    异常组基类
     ├── GeneratorExit                         生成器退出
     ├── KeyboardInterrupt                     键盘中断(通常是输入^C)
     ├── SystemExit                            解释器退出
     └── Exception                             一般异常基类
          ├── ArithmeticError                  计算错误基类
          │    ├── FloatingPointError          浮点错误
          │    ├── OverflowError               溢出错误,数值计算超出表示范围
          │    └── ZeroDivisionError           除零错误
          ├── AssertionError                   断言错误,断言语句断言失败
          ├── AttributeError                   属性错误,访问对象没有的属性
          ├── BufferError                      缓冲区错误
          ├── EOFError                         EOF错误
          ├── ExceptionGroup [BaseExceptionGroup]
          ├── ImportError                      导入错误
          │    └── ModuleNotFoundError         模块找不到错误
          ├── LookupError                      查找错误,没访问到数据
          │    ├── IndexError                  索引错误,序列中没有该index
          │    └── KeyError                    键错误,字典中没有该key
          ├── MemoryError                      内存错误,内存溢出
          ├── NameError                        名称错误,标识符未声明
          │    └── UnboundLocalError           未绑定的本地变量
          ├── OSError                          操作系统错误
          │    ├── BlockingIOError             阻塞IO错误
          │    ├── ChildProcessError           子进程错误
          │    ├── ConnectionError             连接错误
          │    │    ├── BrokenPipeError        
          │    │    ├── ConnectionAbortedError 连接中止错误
          │    │    ├── ConnectionRefusedError 连接拒绝错误
          │    │    └── ConnectionResetError   连接重置错误
          │    ├── FileExistsError             文件已存在错误
          │    ├── FileNotFoundError           文件找不到错误
          │    ├── InterruptedError            中断错误
          │    ├── IsADirectoryError           是一个文件夹错误
          │    ├── NotADirectoryError          不是一个文件夹错误
          │    ├── PermissionError             权限错误
          │    ├── ProcessLookupError          进程查找错误
          │    └── TimeoutError                超时错误
          ├── ReferenceError                   引用错误,弱引用访问已经被GC的对象
          ├── RuntimeError                     运行时错误
          │    ├── NotImplementedError         未实现错误,方法未实现
          │    └── RecursionError              递归错误
          ├── StopAsyncIteration               停止异步迭代
          ├── StopIteration                    停止迭代
          ├── SyntaxError                      语法错误
          │    └── IndentationError            缩进错误
          │         └── TabError               Tab错误,与space混用
          ├── SystemError                      系统错误
          ├── TypeError                        类型错误
          ├── ValueError                       值错误
          │    └── UnicodeError                Unicode错误
          │         ├── UnicodeDecodeError     Unicode解码错误
          │         ├── UnicodeEncodeError     Unicode编码错误
          │         └── UnicodeTranslateError  Unicode转换错误
          └── Warning                          警告基类
               ├── BytesWarning	               bytes和bytearray相关警告的基类
               ├── DeprecationWarning          弃用警告
               ├── EncodingWarning             编码警告
               ├── FutureWarning               未来警告,未来版本中可能会发生变化
               ├── ImportWarning               导入警告
               ├── PendingDeprecationWarning   即将弃用警告
               ├── ResourceWarning             资源警告
               ├── RuntimeWarning              运行时警告
               ├── SyntaxWarning               语法警告
               ├── UnicodeWarning              Unicode警告
               └── UserWarning                 用户警告
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
  • 相关阅读:
    使用Spark读写Parquet文件验证Parquet自带表头的性质及NULL值来源【Java】
    Java线程常见方法
    Linux系统内核概述
    PHP自动执行下一页脚本
    Android ContentProvider
    tup()是什么意思
    m基于matlab的DQPSK调制解调技术的仿真
    365天挑战LeetCode1000题——Day 055 用户分组
    芯片工程师求职题目之CPU篇(4)
    世界银行使用.NET 7开发的免费电子问卷制作系统Survey Solution
  • 原文地址:https://blog.csdn.net/UZDW_/article/details/132725180