我正在用Python编写一个命令行实用程序,因为它是生产代码,所以应该能够干净地关闭,而不会在屏幕上转储一堆东西(错误代码、堆栈跟踪等)。这意味着我需要捕捉键盘中断。
我试过使用两个try-catch块,比如:
if __name__ == '__main__':
try:
main()
except KeyboardInterrupt:
print 'Interrupted'
sys.exit(0)
并捕捉信号本身(如本文所述):
import signal
import sys
def sigint_handler(signal, frame):
print 'Interrupted'
sys.exit(0)
signal.signal(signal.SIGINT, sigint_handler)
在正常操作过程中,这两种方法似乎都很有效。然而,如果中断发生在应用程序末尾的清理代码期间,Python似乎总是在屏幕上打印一些内容。捕捉到中断会产生
^CInterrupted
Exception KeyboardInterrupt in <bound method MyClass.__del__ of <path.to.MyClass object at 0x802852b90>> ignored
而处理该信号会产生
^CInterrupted
Exception SystemExit: 0 in <Finalize object, dead> ignored
或
^CInterrupted
Exception SystemExit: 0 in <bound method MyClass.__del__ of <path.to.MyClass object at 0x802854a90>> ignored
这些错误不仅很难看,而且没有太大帮助(尤其是对于没有源代码的最终用户)!
这个应用程序的清理代码相当大,所以真正的用户很有可能会遇到这个问题。有没有办法捕捉或阻止这个输出,或者这只是我必须处理的事情?
检查这个线程,它有一些关于退出和回溯的有用信息。
如果你对杀死程序更感兴趣,可以尝试这样的方法(这也会从清理代码中去掉腿):
if __name__ == '__main__':
try:
main()
except KeyboardInterrupt:
print('Interrupted')
try:
sys.exit(130)
except SystemExit:
os._exit(130)
[编辑以更改注释中建议的退出代码。130是通常在Linux上为Ctrl-C终止的脚本返回的代码。我们可能不在Linux上,但重要的是返回一个非零值,130和任何值一样好。]
您可以在关闭开始后忽略SIGINT,方法是在启动清理代码之前调用signal.signal(signal.SIGINT, signal.SIG_IGN)
。