有没有办法防止从 sys.exit()引发的 SystemExit 异常被捕获?

文档说调用 sys.exit ()会引发一个 SystemExit 异常,这个异常可以在外部级别捕获。我遇到了这样一种情况: 我希望确定无疑地从测试用例中退出,但是单元测试模块会捕获 SystemExit 并阻止退出。这通常是很好的,但是我试图处理的特定情况是我们的测试框架检测到它被配置为指向一个非测试数据库。在这种情况下,我希望退出并防止运行任何进一步的测试。当然,由于 unittest 陷入了 SystemExit 并继续愉快地向它的方向发展,所以它阻碍了我。

到目前为止,我想到的唯一选择是直接使用 ctype 或类似于 call exit (3)的东西,但是对于一些应该非常简单的东西来说,这似乎是一个相当丑陋的黑客技巧。

73968 次浏览

您可以调用 os._exit()直接退出,而不引发异常:

import os
os._exit(1)

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

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

如果你的问题是 SystemExit被捕获在外部级别(即,单元测试) ,那么 成为外在的自己包装你的主代码在一个 try/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,它是 记录在案,以及所有内置异常的属性。

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

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