如何禁止显示后续异常的父异常(原因)

use*_*797 10 python exception-handling exception python-3.x

我知道raise ... from None并已阅读当我在响应中提出自己的异常时,如何更容易地抑制先前的异常?.

但是,如何在不控制从except子句执行的代码的情况下实现同样的效果(抑制"处理上述异常,发生另一个异常"消息)?我认为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
Run Code Online (Sandbox Code Playgroud)

当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: ...
Run Code Online (Sandbox Code Playgroud)

这是误导性的,因为原始KeyError根本不是一个错误.我当然可以通过将try/except(EAFP)更改为密钥存在的测试(LBYL)来避免这种情况,但这不是非常Pythonic且不太线程友好(不是上面的线程安全,但是那是除此之外).

期望some_api中的所有代码都将其更改raise Xraise X from None(并且在所有情况下甚至都没有意义)是不合理的.是否有一个干净的解决方案来避免错误消息中不需要的异常链?

(顺便说一下,奖励问题:我在示例中使用的缓存事物基本上等同于cache_dict.setdefault(key, some_api.get_the_value_via_web_service_call(key)),如果只有setdefault的第二个参数可以是一个只能在需要设置值时调用的可调用的.是不是有一个更好/规范的方式吗?)

Zac*_*are 8

你有几个选择.

首先,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
Run Code Online (Sandbox Code Playgroud)

对于第二种选择,我假设return value某处隐藏着你没有显示的地方:

try:
    return cache_dict[key]
except KeyError:
    pass
value = cache_dict[key] = some_api.get_the_value(key)
return value
Run Code Online (Sandbox Code Playgroud)

第三种选择,LBYL:

if key not in cache_dict:
    cache_dict[key] = some_api.get_the_value(key)
return cache_dict[key]
Run Code Online (Sandbox Code Playgroud)

对于奖金问题,定义您自己的dict子类,定义__missing__:

class MyCacheDict(dict):

    def __missing__(self, key):
        value = self[key] = some_api.get_the_value(key)
        return value
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助!

  • 谢谢。您的第一个建议存在以下问题:1)它可能会抑制比应有的更多内容(也许 API 代码中有一个有用的上下文,应该在跟踪库中列出),2)它掩盖了异常的来源(而不是将 API 中的模块视为回溯中的最后一行,用户现在将看到我的代码,并且 API 将是最后一行)。尽管如此,在没有 sys.exc_clear() 的情况下,它是迄今为止我见过的所有解决方案中我的首选解决方案。 (2认同)