明明已用try-catch捕获KeyError,为何仍抛出该异常?
问题
自定义类FancyTuple访问不存在的属性a.chal时,明明在__getattr__方法中捕获了KeyError并抛出AttributeError,但异常栈仍会显示KeyError的相关信息,如何消除这个多余的异常栈条目?
代码示例
class FancyTuple: mapping = {1:"first", 2:"second", 3:"third", 4:"fourth", 5:"fifth"} reverseMapping = {"first": 1, "second": 2, "third": 3, "fourth":4 , "fifth": 5} def __init__(self, *args): self._values = args for i, arg in enumerate(args): setattr(self, f"{self.mapping[i+1]}", arg) def __getattr__(self, name): try: index = self.reverseMapping[name] - 1 except KeyError: raise AttributeError(f"'{type(self).__name__}' object has no attribute '{name}'") try: return self._values[index] except IndexError: raise AttributeError(f"'{type(self).__name__}' object has no attribute '{name}'") def __len__(self): return len(self._values)
异常栈信息
--------------------------------------------------------------------------- KeyError Traceback (most recent call last) /var/folders/3t/wf6fblsn3b9byqx75s_l8g300000gn/T/ipykernel_27328/2978799403.py in __getattr__(self, name) 11 try: ---> 12 index = self.reverseMapping[name] - 1 13 except KeyError: KeyError: 'chal' During handling of the above exception, another exception occurred: AttributeError Traceback (most recent call last) /var/folders/3t/wf6fblsn3b9byqx75s_l8g300000gn/T/ipykernel_27328/2705563914.py in <module> ----> 1 a.chal /var/folders/3t/wf6fblsn3b9byqx75s_l8g300000gn/T/ipykernel_27328/2978799403.py in __getattr__(self, name) 12 index = self.reverseMapping[name] - 1 13 except KeyError: ---> 14 raise AttributeError(f"'{type(self).__name__}' object has no attribute '{name}'") 15 16 try: AttributeError: 'FancyTuple' object has no attribute 'chal'
解决方法
这是Python默认保留异常上下文导致的——抛出新异常时,原始触发的KeyError会被作为上下文保留并显示在栈信息里。要消除这个条目,只需在raise语句后加上from None,切断异常上下文的关联。
修改后的__getattr__方法:
def __getattr__(self, name): try: index = self.reverseMapping[name] - 1 except KeyError: raise AttributeError(f"'{type(self).__name__}' object has no attribute '{name}'") from None try: return self._values[index] except IndexError: raise AttributeError(f"'{type(self).__name__}' object has no attribute '{name}'") from None
修改后再访问不存在的属性,异常栈只会显示最终的AttributeError,不会再出现KeyError的相关内容。
另外,也可以用dict.get()方法提前避免触发KeyError,简化代码逻辑:
def __getattr__(self, name): idx = self.reverseMapping.get(name) if idx is None: raise AttributeError(f"'{type(self).__name__}' object has no attribute '{name}'") index = idx - 1 try: return self._values[index] except IndexError: raise AttributeError(f"'{type(self).__name__}' object has no attribute '{name}'") from None
内容的提问来源于stack exchange,提问作者Sairam Tabibu
相关产品推荐
相关产品推荐

