Re-raise exception with a different type and message, preserving existing information
我正在编写一个模块,希望对它可以引发的异常(例如,对于所有
我需要的是对捕获的异常进行"包装",使其具有不同的类型和消息,以便通过捕获异常的内容在传播层次结构上进一步提供信息。但我不想丢失现有的类型、消息和堆栈跟踪;这对于试图调试问题的人来说都是有用的信息。一个顶级的异常处理程序是不好的,因为我正在尝试在异常进一步向上传播堆栈之前对其进行修饰,而顶级处理程序太晚了。
这部分是通过从现有类型(如
python的pep 3134"异常链接和嵌入式跟踪"讨论了python 3.0中为"链接"异常对象接受的更改,以指示在处理现有异常期间引发了新的异常。
我要做的是相关的:我需要它也在早期的Python版本中工作,我不需要它用于链接,而只需要它用于多态性。正确的方法是什么?
python3引入了异常链接(如pep 3134中所述)。这允许在引发异常时将现有异常作为"原因"引用:
1 2 3 4 | try: frobnicate() except KeyError as exc: raise ValueError("Bad grape") from exc |
因此,捕获的异常成为新异常的一部分(即"原因"),并可用于捕获新异常的任何代码。
通过使用此功能,可以设置
在Python2中,这个用例似乎没有很好的答案(如IanBicking和NedBatchelder所描述)。真倒霉。
您可以使用sys.exc_info()获取跟踪,并使用所述跟踪引发新的异常(如PEP提到的)。如果要保留旧的类型和消息,可以在异常上执行此操作,但只有当捕获异常的对象查找它时,这才有用。
例如
1 2 3 4 5 6 7 | import sys def failure(): try: 1/0 except ZeroDivisionError, e: type, value, traceback = sys.exc_info() raise ValueError, ("You did something wrong!", type, value), traceback |
当然,这真的没那么有用。如果是的话,我们就不需要那种活力了。我不建议你这么做。
您可以创建自己的异常类型,扩展您捕获的任何异常。
1 2 3 4 5 6 7 8 9 | class NewException(CaughtException): def __init__(self, caught): self.caught = caught try: ... except CaughtException as e: ... raise NewException(e) |
但大多数情况下,我认为捕获异常并处理它会更简单,要么
编辑:我发现了这种分析方法,可以抛出自己的异常并保留原来的异常。没有很好的解决方案。
我还发现,很多时候我需要一些"包装"来纠正错误。
这包含在函数范围内,有时只在函数内换行。
创建了一个包装,用于
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | import inspect from contextlib import contextmanager, ContextDecorator import functools class wrap_exceptions(ContextDecorator): def __init__(self, wrapper_exc, *wrapped_exc): self.wrapper_exc = wrapper_exc self.wrapped_exc = wrapped_exc def __enter__(self): pass def __exit__(self, exc_type, exc_val, exc_tb): if not exc_type: return try: raise exc_val except self.wrapped_exc: raise self.wrapper_exc from exc_val def __gen_wrapper(self, f, *args, **kwargs): with self: for res in f(*args, **kwargs): yield res def __call__(self, f): @functools.wraps(f) def wrapper(*args, **kw): with self: if inspect.isgeneratorfunction(f): return self.__gen_wrapper(f, *args, **kw) else: return f(*args, **kw) return wrapper |
使用实例装饰者
1 2 3 | @wrap_exceptions(MyError, IndexError) def do(): pass |
调用
1 2 3 4 | try: do() except MyError as my_err: pass # handle error |
上下文管理器
1 2 3 4 | def do2(): print('do2') with wrap_exceptions(MyError, IndexError): do() |
在
最能满足您需求的解决方案应该是:
1 2 3 4 5 | try: upload(file_id) except Exception as upload_error: error_msg ="Your upload failed! File:" + file_id raise RuntimeError(error_msg, upload_error) |
通过这种方式,您可以稍后打印您的消息,以及上载函数所引发的特定错误。