Как подавить отображение родительского исключения (причины) для последующих исключений
Я в курсе raise ... from None
и читал как я могу более легко подавлять предыдущие исключения, когда я поднимаю свое собственное исключение в ответ?.
однако, как я могу достичь того же эффекта (подавления сообщения "во время обработки вышеуказанного исключения произошло другое исключение"), не имея контроля над кодом, который выполняется из предложения except? Я так и думал!--3--> может использоваться для этого, но эта функция не существует в 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), но это не очень Питоническое и менее потокобезопасное (не то вышеизложенное является потокобезопасным, как есть, но это к делу не относится).
неразумно ожидать, что весь код в some_api изменит их raise X
до raise X from None
(и это даже не имеет смысла во всех случаях). Есть ли чистое решение, чтобы избежать нежелательной цепочки исключений в сообщении об ошибке?
(кстати, бонусный вопрос: кэш, который я использовал в Примере, в основном эквивалентен cache_dict.setdefault(key, some_api.get_the_value_via_web_service_call(key))
, если бы только второй аргумент setdefault мог быть вызываемым, что бы вызывается только тогда, когда необходимо задать значение. Разве нет лучшего / канонического способа сделать это?)
2 ответов
у вас есть несколько вариантов здесь.
во-первых, более чистая версия того, что предложил 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
надеюсь, что это помогает!
вы можете попробовать подавить контекст самостоятельно:
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