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