如何抑制显示后续异常的父异常(原因)
How to suppress displaying the parent exception (the cause) for subsequent exceptions
我知道 raise ... from None
并已阅读 How can I more easily suppress previous exceptions when I raise my own exception in response?。
但是,如何在不控制从 except 子句执行的代码的情况下实现相同的效果(抑制 "During handling of the above exception, another exception occurred" 消息)?我认为 sys.exc_clear()
可以用于此,但 Python 中不存在该功能 3.
我为什么要问这个?我有一些简单的缓存代码,看起来像(简化):
try:
value = cache_dict[key]
except KeyError:
value = some_api.get_the_value_via_web_service_call(key)
cache_dict[key] = value
当 API 调用出现异常时,输出将是这样的:
Traceback (most recent call last):
File ..., line ..., in ...
KeyError: '...'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File ..., line ..., in ...
some_api.TheInterestingException: ...
这是一种误导,因为原来的 KeyError 根本不是真正的错误。我当然可以通过将 try/except (EAFP) 更改为密钥存在测试 (LBYL) 来避免这种情况,但这不是很 Pythonic 并且线程友好性较低(不是上面的线程-安全,但这不是重点)。
期望 some_api 中的所有代码将它们的 raise X
更改为 raise X from None
是不合理的(而且它在所有情况下都没有意义)。是否有一个干净的解决方案来避免错误消息中不需要的异常链?
(顺便说一句,奖金问题:我在示例中使用的缓存东西基本上等同于 cache_dict.setdefault(key, some_api.get_the_value_via_web_service_call(key))
,如果只有 setdefault 的第二个参数可以是可调用的,并且只有在值需要设置。没有更好/规范的方法吗?)
您可以尝试自己抑制上下文:
try:
value = cache_dict[key]
except KeyError:
try:
value = some_api.get_the_value_via_web_service_call(key)
except Exception as e:
e.__context__ = None
raise
cache_dict[key] = value
这里有几个选项。
首先,orlp 建议的更清晰的版本:
try:
value = cache_dict[key]
except KeyError:
try:
value = some_api.get_the_value(key)
except Exception as e:
raise e from None
cache_dict[key] = value
对于第二个选项,我假设有一个 return value
隐藏在你没有显示的地方:
try:
return cache_dict[key]
except KeyError:
pass
value = cache_dict[key] = some_api.get_the_value(key)
return value
第三个选项,LBYL:
if key not in cache_dict:
cache_dict[key] = some_api.get_the_value(key)
return cache_dict[key]
对于奖金问题,定义你自己的dict子类定义__missing__
:
class MyCacheDict(dict):
def __missing__(self, key):
value = self[key] = some_api.get_the_value(key)
return value
希望对您有所帮助!
这是@Zachary 的第二个选项的一个版本,它的使用稍微简单一些。首先,dict 的一个辅助子类,它 returns 一个“未命中”的标志值而不是抛出异常:
class DictCache(dict):
def __missing__(self, key):
return self
当时正在使用:
cache = DictCache()
...
value = cache[K]
if value is cache:
value = cache[K] = some_expensive_call(K)
请注意使用“is”而不是“==”以确保不会与有效条目发生冲突。
如果赋值的是一个简单的变量(即“值”而不是另一个变量“x.value”的属性),你甚至可以只写两行:
if (value := cache[K]) is cache:
value = cache[K] = some_expensive_call(K)
我知道 raise ... from None
并已阅读 How can I more easily suppress previous exceptions when I raise my own exception in response?。
但是,如何在不控制从 except 子句执行的代码的情况下实现相同的效果(抑制 "During handling of the above exception, another exception occurred" 消息)?我认为 sys.exc_clear()
可以用于此,但 Python 中不存在该功能 3.
我为什么要问这个?我有一些简单的缓存代码,看起来像(简化):
try:
value = cache_dict[key]
except KeyError:
value = some_api.get_the_value_via_web_service_call(key)
cache_dict[key] = value
当 API 调用出现异常时,输出将是这样的:
Traceback (most recent call last):
File ..., line ..., in ...
KeyError: '...'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File ..., line ..., in ...
some_api.TheInterestingException: ...
这是一种误导,因为原来的 KeyError 根本不是真正的错误。我当然可以通过将 try/except (EAFP) 更改为密钥存在测试 (LBYL) 来避免这种情况,但这不是很 Pythonic 并且线程友好性较低(不是上面的线程-安全,但这不是重点)。
期望 some_api 中的所有代码将它们的 raise X
更改为 raise X from None
是不合理的(而且它在所有情况下都没有意义)。是否有一个干净的解决方案来避免错误消息中不需要的异常链?
(顺便说一句,奖金问题:我在示例中使用的缓存东西基本上等同于 cache_dict.setdefault(key, some_api.get_the_value_via_web_service_call(key))
,如果只有 setdefault 的第二个参数可以是可调用的,并且只有在值需要设置。没有更好/规范的方法吗?)
您可以尝试自己抑制上下文:
try:
value = cache_dict[key]
except KeyError:
try:
value = some_api.get_the_value_via_web_service_call(key)
except Exception as e:
e.__context__ = None
raise
cache_dict[key] = value
这里有几个选项。
首先,orlp 建议的更清晰的版本:
try:
value = cache_dict[key]
except KeyError:
try:
value = some_api.get_the_value(key)
except Exception as e:
raise e from None
cache_dict[key] = value
对于第二个选项,我假设有一个 return value
隐藏在你没有显示的地方:
try:
return cache_dict[key]
except KeyError:
pass
value = cache_dict[key] = some_api.get_the_value(key)
return value
第三个选项,LBYL:
if key not in cache_dict:
cache_dict[key] = some_api.get_the_value(key)
return cache_dict[key]
对于奖金问题,定义你自己的dict子类定义__missing__
:
class MyCacheDict(dict):
def __missing__(self, key):
value = self[key] = some_api.get_the_value(key)
return value
希望对您有所帮助!
这是@Zachary 的第二个选项的一个版本,它的使用稍微简单一些。首先,dict 的一个辅助子类,它 returns 一个“未命中”的标志值而不是抛出异常:
class DictCache(dict):
def __missing__(self, key):
return self
当时正在使用:
cache = DictCache()
...
value = cache[K]
if value is cache:
value = cache[K] = some_expensive_call(K)
请注意使用“is”而不是“==”以确保不会与有效条目发生冲突。
如果赋值的是一个简单的变量(即“值”而不是另一个变量“x.value”的属性),你甚至可以只写两行:
if (value := cache[K]) is cache:
value = cache[K] = some_expensive_call(K)