Python 是否可以从已经捕获异常的外部代码中捕获异常?

Python 是否可以从已经捕获异常的外部代码中捕获异常?,python,error-handling,Python,Error Handling,这是一个很难回答的问题,但这里有一个简单的情况。我正在使用一些接受回调的库代码。它有自己的错误处理,如果在执行回调时出现任何错误,就会引发错误 类库异常(异常): 通过 def library_函数(回调,字符串): 尝试: #(这里有其他东西) 回调(字符串) 除: 引发LibraryException('库代码遇到问题') 我在输入循环中使用这段代码。根据输入中的值,我知道回调函数中可能出现的潜在错误。如果发生这种情况,在从错误消息中得到有用的反馈后,我想重新编程。我想象它看起来像这样:

这是一个很难回答的问题,但这里有一个简单的情况。我正在使用一些接受回调的库代码。它有自己的错误处理,如果在执行回调时出现任何错误,就会引发错误

类库异常(异常):
通过
def library_函数(回调,字符串):
尝试:
#(这里有其他东西)
回调(字符串)
除:
引发LibraryException('库代码遇到问题')
我在输入循环中使用这段代码。根据输入中的值,我知道回调函数中可能出现的潜在错误。如果发生这种情况,在从错误消息中得到有用的反馈后,我想重新编程。我想象它看起来像这样:

class MyException(Exception):
    pass

def my_callback(string):
    raise MyException("Here's some specific info about my code hitting a problem.")

while True:
    something = input('Enter something: ')
    try:
        library_function(my_callback, something)
    except MyException as e:
        print(e)
        continue
当然,这不起作用,因为
MyException
将在
library\u函数中被捕获,这将引发自身的
异常(信息量要小得多)
并停止程序

显然要做的事情是在调用
library\u函数之前验证输入,但这是一个循环问题,因为解析是我首先使用库代码的目的。(对于好奇的人来说,这是一个问题,但我认为我的问题不够具体,无法保证把所有具体细节都弄得乱七八糟。)

另一种方法是修改代码以捕获任何错误(或至少捕获库生成的错误类型),并直接打印内部错误消息:

def my_callback(string):
    error_str = "Here's some specific info about my code hitting a problem."
    print(error_str)
    raise MyException(error_str)

while True:
    something = input('Enter something: ')
    try:
        library_function(my_callback, something)
    except LibraryException:
        continue
但我认为这有两个问题。一个是我在撒网,可能会捕捉并忽略我瞄准范围以外的错误。除此之外,似乎。。。打印错误消息,然后将异常本身抛出到空白中,这是不雅观的、不自然的。另外,命令行事件循环仅用于测试;最终,我计划将其嵌入到GUI应用程序中,在没有打印输出的情况下,我仍然希望访问并显示出错的信息


实现这样的目标,最干净、最有吸引力的方法是什么?

实现你想要的目标似乎有很多方法。不过,哪一个更健壮呢?我找不到关于它的线索。我将尝试解释所有对我来说显而易见的方法。也许你会发现其中一个很有用

我将使用您提供的示例代码来演示这些方法,这里有一个关于其外观的更新-

类MyException(异常):
通过
def my_回调(字符串):
引发MyException(“这里有一些关于我的代码遇到问题的特定信息。”)
def library_函数(回调,字符串):
尝试:
#(这里有其他东西)
回调(字符串)
除:
引发异常('库代码遇到问题')
最简单的方法是:
导入回溯
尝试:
库函数(我的回调'boo!')
除:
#注意:请记住将'format_exc'的'chain'参数设置为'True'(默认值)
tb_info=traceback.format_exc()
这不需要太多关于异常和堆栈跟踪本身的知识,也不需要向库函数传递任何特殊的帧/回溯/异常。但是看看它会返回什么(比如,
tb\u info
的值)-

“”
回溯(最近一次呼叫最后一次):
库函数中第14行的文件“path/to/test.py”
回调(字符串)
文件“path/to/test.py”,第9行,在my_回调中
引发MyException(“这里有一些关于我的代码遇到问题的特定信息。”)
MyException:这里有一些关于我的代码遇到问题的具体信息。
在处理上述异常期间,发生了另一个异常:
回溯(最近一次呼叫最后一次):
文件“path/to/test.py”,第19行,在
库函数(我的回调'boo!')
库函数中第16行的文件“path/to/test.py”
引发异常('库代码遇到问题')
异常:库代码遇到问题。
'''
这是一个字符串,如果你只是让异常发生而不捕获,你会看到同样的东西。注意这里的异常链接,顶部的异常是发生在底部异常之前的异常。您可以解析出所有异常名称-

重新导入
异常列表=re.findall(r'^(\w+):(\w+),tb\u信息,标志=re.M)
这样,您将在
异常列表中获得
[('MyException',“这里有一些关于我的代码遇到问题的特定信息”),('Exception',库代码遇到问题')]

虽然这是最简单的解决方法,但它不太了解上下文。我的意思是,你得到的只是字符串形式的类名。不管怎样,如果这是适合你的需要-我不认为这有什么问题

“稳健”方法-通过
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu上下文
/
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
Python本身跟踪异常跟踪历史、当前的异常、导致此异常的异常等等。您可以在中了解这个概念的复杂细节

无论您是否阅读了整个PEP,我敦促您至少熟悉隐式链接异常显式链接异常。也许这会有用

作为一个小复习,
raise。。。from
用于显式链接异常。您在示例中展示的方法是隐式链接

现在,您需要做一个心理记录-用于显式链接异常,用于隐式链接异常。由于您的示例使用隐式链接,您只需向后跟随
\uuuuu context\uuuu
,就可以到达
MyException
。事实上,由于这只是一个嵌套级别,您将立即达到它

导入系统 导入回溯 尝试: 库函数(我的回调'boo!')
<class 'Exception'>
<class '__main__.MyException'>