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

How to suppress displaying the parent exception (the cause) for subsequent exceptions

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

但是,如何在不控制从except子句执行的代码的情况下实现相同的效果(抑制"在处理上述异常时,发生了另一个异常"消息)?我认为sys.exc_clear()可以用于此目的,但该函数在Python3中不存在。

我为什么要问这个?我有一些简单的缓存代码,看起来像(简化的):

1
2
3
4
5
try:
    value = cache_dict[key]
except KeyError:
    value = some_api.get_the_value_via_web_service_call(key)
    cache_dict[key] = value

当API调用中出现异常时,输出将如下所示:

1
2
3
4
5
6
7
8
9
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)的测试来避免这种情况,但这并不是非常Python式的,对线程不太友好(不是说上面的内容是线程安全的,但这不是重点)。

期望某些API中的所有代码将它们的raise X更改为raise X from None,这是不合理的(而且在所有情况下都没有意义)。是否有一个干净的解决方案来避免错误消息中不需要的异常链?

(顺便说一句,奖金问题:我在示例中使用的缓存内容基本上等同于cache_dict.setdefault(key, some_api.get_the_value_via_web_service_call(key)),如果setdefault的第二个参数可以是一个可调用的参数,那么只有在需要设置该值时才会调用该参数。难道没有更好的/规范的方法吗?)


你有几个选择。

首先,ORLP建议的更清晰版本:

1
2
3
4
5
6
7
8
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藏在你没有看到的地方:

1
2
3
4
5
6
try:
    return cache_dict[key]
except KeyError:
    pass
value = cache_dict[key] = some_api.get_the_value(key)
return value

第三种选择,lbyl:

1
2
3
if key not in cache_dict:
    cache_dict[key] = some_api.get_the_value(key)
return cache_dict[key]

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

1
2
3
4
5
class MyCacheDict(dict):

    def __missing__(self, key):
        value = self[key] = some_api.get_the_value(key)
        return value

希望这有帮助!


您可以尝试自己抑制上下文:

1
2
3
4
5
6
7
8
9
10
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