我正在尝试在except:
块中引发异常但是解释器试图提供帮助并通过“强制”打印堆栈跟踪。有可能避免这种情况吗?
一些背景资料:
我正在玩urwid,一个TUI library用于python。用户界面通过调用urwid.MainLoop.run()
启动,并以提升 urwid.ExitMainLoop()
结束。到目前为止,这工作正常但是当引发另一个异常时会发生什么?例如。当我正在捕捉KeyboardInterrupt
(urwid MainLoop没有)时,我做了一些清理并希望结束用户界面 - 通过引发适当的异常。但这会导致屏幕上出现堆栈痕迹。
一些小小的研究表明,python3会记住链式异常,并且可以使用'cause'显式引发异常:raise B() from A()
。我学会了一些方法来更改或附加有关引发异常的数据,但我发现无法“禁用”此功能。我想避免打印像The above exception was the direct cause of...
那样的堆栈跟踪和行,只是在except:
块中引发接口结束异常,就像我在一个块外面一样。
这是可能还是我做了一些根本错误的事情?
修改: 这是一个类似于我当前架构的示例,导致同样的问题:
#!/usr/bin/env python3
import time
class Exit_Main_Loop(Exception):
pass
# UI main loop
def main_loop():
try:
while True:
time.sleep(0.1)
except Exit_Main_Loop as e:
print('Exit_Main_Loop')
# do some UI-related clean up
# my main script
try:
main_loop()
except KeyboardInterrupt as e:
print('KeyboardInterrupt')
# do some clean up
raise Exit_Main_Loop() # signal the UI to terminate
很遗憾,除了main_loop
之外,我无法将KeyboardInterrupt
更改为{{1}}。有没有解决这个问题的模式?
答案 0 :(得分:1)
我仍然不太明白你的解释,但是来自代码:
try:
main_loop()
except KeyboardInterrupt as e:
print('KeyboardInterrupt')
# do some clean up
raise Exit_Main_Loop() # signal the UI to terminate
main_loop
无法看到Exit_Main_Loop()
例外情况。当您到达KeyboardInterrupt
句柄时,main_loop
保证已经完成(在这种情况下,由于未处理的KeyboardInterrupt
),因此其异常处理程序不再处于活动状态。
所以,会发生什么事情,你提出了一个没有人抓住的新例外。当异常在没有处理的情况下到达代码顶部时,Python会通过打印回溯和退出来自动处理它。
如果您想将一种类型的异常转换为另一种类型,以便main_loop
可以处理它,您必须在内部 try
块中执行此操作。
你说:
不幸的是,除了KeyboardInterrupt之外,我无法将main_loop更改为。
如果这是真的,那么对你的问题没有真正的答案......但我不确定首先出现问题,除了你创建的问题。只需从代码中删除Exit_Main_Loop()
,是不是已经按照您的要求执行了操作?如果您只是想阻止Python打印回溯并退出,那么这将为您解决。
如果确实存在 问题 - 例如,main_loop
代码有一些清理代码,无论如何都需要执行,并且它没有被执行,因为它没有句柄KeyboardInterrupt
- 有两种方法可以解决这个问题。
首先,正如signal
文档解释:
signal.signal()
函数允许定义在接收到信号时要执行的自定义处理程序。安装了少量默认处理程序:...SIGINT
已转换为KeyboardInterrupt
例外。
因此,您所要做的就是用另一个处理程序替换默认处理程序:
def handle_sigint(signum, frame):
raise ExitMainLoop()
signal.signal(signal.SIGINT, handle_sigint)
在你开始main_loop
之前做这个,你应该没问题。请记住,线程程序和Windows都有一些限制,但如果这些限制都不适用,那么你就是金色的; ctrl-C将触发ExitMainLoop
异常而不是KeyboardInterrupt
,因此主循环将处理它。 (您可能还希望在包装器代码中添加except ExitMainLoop:
块,以防 main_loop
之外的异常。但是,您可以轻松编写contextmanager
设置和恢复调用main_loop
周围的信号,因此没有任何外部代码可以提升它。)
或者,即使您无法编辑main_loop
源代码,也可以始终在运行时对其进行monkeypatch。在不知道代码是什么样的情况下,不可能完全解释如何做到这一点,但几乎总有办法做到这一点。