语言基础篇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

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]

单异常处理

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
# 三个子异常

异常组处理

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) 
# # 但在异常组中不带()会报异常

返回值机制

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. try-except各个子块下变量在同一个命名空间

    # 报错
    i = 0
    def func():
        i += 2
        print(i)
    func()
    
    # 不报错
    try:
        i = 0
    except Exception():
        ...
    else:
        i += 1
    finally:
        i += 1
    print(i)
    

内置异常层次结构

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                 用户警告

你可能感兴趣的:(Python,python,开发语言)