我正在写一个模块,希望有一个统一的异常层次结构来处理它可能引发的异常(例如,从FooError
抽象类继承foo
模块的所有特定异常),这允许模块的用户捕获这些特定的异常,并在需要时区别处理它们,但是从模块引发的许多异常是因为其他异常而引发的;例如,由于文件上的OSError而导致某个任务失败。
我需要的是**“ Package ”捕获的异常,使其具有不同的类型和消息**,这样无论捕获异常的是什么,信息都可以在传播层次结构的更上层得到,但我不想丢失现有的类型、消息和堆栈跟踪;对于试图调试问题的人来说,这些都是有用的信息,顶级异常处理程序是不好的,因为我试图在异常进入传播堆栈之前修饰它,而顶级处理程序为时已晚。
通过从现有类型(例如class FooPermissionError(OSError, FooError)
)派生模块foo
的特定异常类型,可以部分解决这一问题,但这并不能使将现有异常示例 Package 为新类型或修改消息变得更容易。
Python的PEP 3134“异常链接和嵌入式回溯”讨论了Python 3.0中接受的一个改变,即“链接”异常对象,以指示在处理现有异常的过程中引发了一个新的异常。
我想做的是相关的:我需要它在Python早期版本中也能工作,而且我不需要它来链接,而只需要它来多态。
7条答案
按热度按时间b4lqfgs41#
Python 3引入了异常链接(如PEP 3134中所描述的),这允许在引发异常时引用一个现有的异常作为“原因”:
捕获的异常(
exc
,一个KeyError)因此成为新异常ValueError的一部分(是其“原因”)。“原因”可用于捕获新异常的任何代码。通过使用这个特性,
__cause__
属性被设置,内置的异常处理器也知道如何报告异常的“原因”和“上下文”沿着回溯。在Python 2中,这个用例似乎没有好的答案(如Ian Bicking和Ned Batchelder所描述的)。
4dc9hkyq2#
你可以使用sys.exc_info()来获取traceback,然后用traceback引发你的新异常(正如PEP所提到的),如果你想保留旧的类型和消息,你可以在异常上这样做,但是这只有在捕获你的异常的东西寻找它的时候才有用。
例如
当然,这真的没什么用。如果有用的话,我们就不需要PEP了。我不建议这么做。
cld4siwp3#
您可以创建自己的异常类型来扩展捕获的whichever exception。
但是大多数时候,我认为捕获异常,处理它,或者
raise
原始异常(并保留追溯)或者raise NewException()
会更简单。如果我调用你的代码,并且我收到了你的一个自定义异常,我会认为你的代码已经处理了你必须捕获的任何异常。因此我不需要自己访问它。编辑:我发现了this analysis的方法来抛出自己的异常并保留原来的异常。没有漂亮的解决方案。
gajydyqb4#
我还发现,很多时候我需要一些" Package "的错误提出。
这包括在函数作用域中,有时只 Package 函数中的某些行。
已创建用于
decorator
和context manager
的 Package 器:实施
用法示例
装饰工
当调用
do
方法时,不要担心IndexError
,只需考虑MyError
上下文管理器
在
do2
内部,在context manager
中,如果IndexError
被提升,则它将被 Package 并提升MyError
sigwle7e5#
这是题外话,但是在为my own library构建一致的错误消息时,我发现我们在自己的错误消息出现时 Package 了它们,很高兴看到Python 3.11现在提供了add_note函数,用附加信息来增加现有的错误,这可能也是有用的。
对于Python 3.11add_note()
add_note()方法被添加到BaseException中。它可以用来丰富异常的上下文信息,这些信息在引发异常时不可用。添加的注解显示在默认的追溯中。
因此,我们现在遵循的模式是:
eoxn13cs6#
为了真正“转换”异常,避免@bignose的答案所解释的上下文或原因,你必须做一些恶作剧(下面的Python 3):
通过传入traceback,可以使它指向问题发生的位置,而不是
raise
语句。这可能会变成一个上下文,使其更可重用。
请注意,如果您只想更改消息,则可以操作
args
。fgw7neuy7#
满足您需求的最直接解决方案应该是:
通过这种方式,您可以在以后打印消息以及上载函数引发的特定错误