2010-11-17 83 views

回答

122

是的,您可以使用signal module安装中断处理程序。

import signal 
import sys 
import time 

def signal_handler(signal, frame): 
    print 'You pressed Ctrl+C!' 
    sys.exit(0) 

signal.signal(signal.SIGINT, signal_handler) 
print 'Press Ctrl+C' 
while True: 
    time.sleep(1) 
+8

请注意,有一些平台特定的问题与信号模块 - 不应该影响这张海报,但“在Windows上,信号()只能用SIGABRT,SIGFPE,SIGILL,SIGINT,SIGSEGV或SIGTERM来调用,任何其他情况下都会引发ValueError。 – bgporter 2010-11-17 14:39:11

+6

也适用于线程。尽管如此,我希望你永远不要“真实:继续”。 (按照这种风格,无论如何,'虽然真实:通过'会更整洁。)那太浪费了;尝试类似'while True:time.sleep(60 * 60 * 24)'(一次睡一天完全是任意图)。 – 2011-10-06 12:04:30

+1

如果你使用克里斯摩根的建议,使用'时间'(如你应该),不要忘了'进口时间':) – Seaux 2013-05-30 17:37:04

4

您可以防止打印堆栈跟踪KeyboardInterrupt,没有try: ... except KeyboardInterrupt: pass(最明显和最propably“最佳”的解决方案,但你已经知道了,问其他的东西),用sys.excepthook。类似于

def custom_excepthook(type, value, traceback): 
    if type is KeyboardInterrupt: 
     return # do nothing 
    else: 
     sys.__excepthook__(type, value, traceback) 
+0

我想干净退出,不留痕迹如果用户按ctrl-c – Alex 2010-11-17 14:29:43

+0

catched ==>抓到 – 2010-11-17 14:51:26

+7

这根本不是真的。 KeyboardInterrupt异常是在中断处理程序中创建的。 SIGINT的默认处理程序引发了KeyboardInterrupt,所以如果您不想要这种行为,您只需为SIGINT提供一个不同的信号处理程序。你的观点是正确的,只有在尝试中才能处理异常情况,但是在这种情况下,你可以将异常从头开始。 – Matt 2012-12-20 14:17:50

25

如果你想要的是不显示的回溯,使你的代码是这样的:

## all your app logic here 
def main(): 
    ## whatever your app does. 


if __name__ == "__main__": 
    try: 
     main() 
    except KeyboardInterrupt: 
     # do nothing here 
     pass 

(是的,我知道这并不直接回答这个问题,但它不是真的清楚为什么需要尝试/除了块是令人反感的 - 也许这使得它不那么烦人的OP)

+2

出于某种原因,这并不总是适用于我。 'signal.signal(signal.SIGINT,lambda s,f:sys.exit(0))'总是这样。 – 2013-07-13 18:15:18

+0

这并不总是适用于诸如使用线程的pygtk之类的东西。有时^ C只会杀死当前线程而不是整个进程,所以异常只会通过该线程传播。 – 2013-10-23 01:56:45

+0

还有另外一个特别关于Ctrl + C与pygtk的问题:http://stackoverflow.com/questions/16410852/keyboard-interrupt-with-with-python-gtk – bgporter 2013-10-23 13:46:56

23

设置自己的信号处理程序的替代方法是使用上下文管理器来捕获异常并忽略它:

>>> class CleanExit(object): 
...  def __enter__(self): 
...    return self 
...  def __exit__(self, exc_type, exc_value, exc_tb): 
...    if exc_type is KeyboardInterrupt: 
...      return True 
...    return exc_type is None 
... 
>>> with CleanExit(): 
...  input() #just to test it 
... 
>>> 

这将删除try - except块,同时保留一些明确提及正在发生的事情。

这也允许您只在代码的某些部分忽略中断,而不必每次都设置和重新设置信号处理程序。

+1

很好,这个解决方案确实似乎有点直接表达目的而不是处理信号。 – Seaux 2013-05-30 17:50:01

4

我知道这是一个老问题,但我先来到这里,然后发现atexit模块。我不知道它的跨平台跟踪记录或完整的注意事项,但到目前为止,它正是我在试图处理Linux上的后清理操作时所需要的。只是想用另一种方式来解决问题。

我想在Fabric操作的上下文中进行出口后清理,因此在try/except中包装所有内容对我来说也不是一种选择。我觉得atexit可能非常适合这种情况,您的代码不在控制流的顶层。

atexit是非常有能力和可读性开箱,例如:

import atexit 

def goodbye(): 
    print "You are now leaving the Python sector." 

atexit.register(goodbye) 

您也可以使用它作为一个装饰(如2.6;本实施例中是从文档):

import atexit 

@atexit.register 
def goodbye(): 
    print "You are now leaving the Python sector." 

如果您只想针对KeyboardInterrupt而设定,另一个人对此问题的回答可能会更好。

但请注意,atexit模块只有70行代码,创建类似的版本以不同的方式处理异常(例如将异常作为参数传递给回调函数)并不困难。(限制atexit这将保证修改版本:目前我无法想象退出回调函数知道异常的方法; atexit处理程序捕获异常,调用您的回调,然后重新调用。-raises是例外,但你可以做不同的这个)

欲了解更多信息,请参阅: