67

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

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

4

3 回答 3

99

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

import os
os._exit(1)

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

于 2008-10-06T06:24:53.900 回答
61

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

如果您的问题SystemExit在外部级别(即单元测试)被捕获,那么您自己就是外部级别!将您的主要代码包装在try/except块中,catchSystemExit并在那里调用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一些读者不知道的,它被记录在案,以及所有内置异常的属性。

于 2012-12-05T12:23:15.827 回答
0

您也可以使用退出,请参见下面的示例:

while True:
print('Type exit to exit.')
response = input()
if response == 'exit':
    quit(0)
print('You typed ' + response + '.')
于 2020-05-20T21:18:30.267 回答