为何`dict(id=1, **{'id':2})`在异常处理中抛出KeyError而非TypeError?
重复关键字参数在except块中异常类型变化的原因
正常情况下,调用dict(id=1, **{'id': 2})会因重复关键字参数抛出TypeError:
In [1]: dict(id=1, **{'id': 2}) --------------------------------------------------------------------------- TypeError Traceback (most recent call last) Input In [1], in <cell line: 1>() ----> 1 dict(id=1, **{'id': 2}) TypeError: dict() got multiple values for keyword argument 'id'
但在处理其他异常的except代码块中执行该语句时,却会抛出KeyError:
In [2]: try: ...: raise ValueError('foo') # 无论抛出何种异常都不影响结果 ...: except: ...: dict(id=1, **{'id': 2}) # 抛出KeyError: 'id' ...: --------------------------------------------------------------------------- ValueError Traceback (most recent call last) Input In [2], in <cell line: 1>() 1 try: ----> 2 raise ValueError('foo') # 无论抛出何种异常都不影响结果 3 except: ValueError: foo During handling of the above exception, another exception occurred: KeyError Traceback (most recent call last) Input In [2], in <cell line: 1>() 2 raise ValueError('foo') # 无论抛出何种异常都不影响结果 3 except: ----> 4 dict(id=1, **{'id': 2}) KeyError: 'id'
这是CPython的底层实现bug,和前置抛出的异常本身无关,只和代码处于异常处理上下文(except/finally/else块)内有关:
- 正常流程中,
dict()构造函数会先检查显式传入的关键字参数和展开的**kwargs是否存在重复,发现重复后抛出TypeError; - 但在异常处理上下文里,解释器的参数检查错误分支逻辑被异常处理机制干扰,原本应该触发的
TypeError被错误转换成了KeyError。
该bug已在CPython 3.9.5、3.10.5、3.11.8版本中复现,最初源于对tortoise-orm相关问题的排查。
内容的提问来源于stack exchange,提问作者Waket Zheng
相关产品推荐
相关产品推荐

