【问题标题】:Is there a way to prevent a SystemExit exception raised from sys.exit() from being caught?有没有办法防止从 sys.exit() 引发的 SystemExit 异常被捕获?
【发布时间】:2010-09-15 10:55:26
【问题描述】:

文档说调用 sys.exit() 会引发一个 SystemExit 异常,该异常可以在外部级别中捕获。我有一种情况,我想明确且毫无疑问地从测试用例内部退出,但是 unittest 模块捕获了 SystemExit 并阻止了退出。这通常很好,但我试图处理的具体情况是我们的测试框架检测到它被配置为指向非测试数据库。在这种情况下,我想退出并阻止运行任何进一步的测试。当然,由于 unittest 捕获了 SystemExit 并愉快地继续前进,它阻碍了我。

到目前为止,我想到的唯一选择是使用 ctypes 或类似于直接调用 exit(3) 的东西,但这对于应该非常简单的东西来说似乎是一个非常丑陋的 hack。

【问题讨论】:

  • 这在尝试从嵌入式 IPython shell 退出程序时也很重要。

标签: python exception exit systemexit


【解决方案1】:

可以调用os._exit()直接退出,不抛出异常:

import os
os._exit(1)

这会绕过所有 python 关闭逻辑,例如 atexit 模块,并且不会运行您在这种情况下试图避免的异常处理逻辑。参数是进程将返回的退出代码。

【讨论】:

  • 在您的 os._exit(1) 调用之前添加打印以明确查看会发生什么。例如:print("Error from my code") os._exit(1)(当然需要写成 2 行)。
【解决方案2】:

正如 Jerub 所说,os._exit(1) 是您的答案。但是,考虑到它绕过所有清理程序,包括finally: 块、关闭文件等,确实应该不惜一切代价避免它。那么我可以介绍一种更安全(-ish)的使用方式吗?

如果您的问题是 SystemExit 在外层被捕获(即单元测试),那么自己成为外层! 将您的主要代码包装在 @987654325 中@/except 阻塞,捕获SystemExit,并在那里调用os._exit()并且在那里!这样您通常可以在代码中的任何位置调用sys.exit ,让它冒泡到顶层,优雅地关闭所有文件并运行所有清理,然后然后调用os._exit

您甚至可以选择哪些出口是“紧急”出口。下面的代码就是这种方法的一个例子:

import sys, os

EMERGENCY = 255  # can be any number actually

try:
    # wrap your whole code here ...
    # ... some code
    if x: sys.exit()
    # ... some more code
    if y: sys.exit(EMERGENCY)  # use only for emergency exits
    ...  # yes, this is valid python!

    # Might instead wrap all code in a function
    # It's a common pattern to exit with main's return value, if any
    sys.exit(main())

except SystemExit as e:
    if e.code != EMERGENCY:
        raise  # normal exit, let unittest catch it at the outer level
else:
    os._exit(EMERGENCY)  # try to stop *that*!

至于有些读者不知道的e.code,就是documented,以及所有内置异常的属性。

【讨论】:

  • 我需要检查的一种情况是代码是否为 0,这表明我们正在尝试正常退出而不会出现错误/崩溃。这在通过 -h arg 使用 OptionParser 时很有用,我不希望 SystemExit 被视为异常。所以,谢谢,你帮我验证了如何通过异常访问退出代码。
  • 这里也一样。我需要检查代码 0,这很有帮助。
  • 这是一种更稳健的方法。谢谢梅斯特
【解决方案3】:

你也可以使用quit,见下例:

while True:
print('Type exit to exit.')
response = input()
if response == 'exit':
    quit(0)
print('You typed ' + response + '.')

【讨论】:

    猜你喜欢
    • 2019-09-19
    • 2019-06-18
    • 2022-06-14
    • 2014-12-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多