Respuestas:
Sí, puede instalar un manejador de interrupciones usando la señal del módulo y esperar eternamente usando un subproceso .
import signal
import sys
import time
import threading
def signal_handler(signal, frame):
print('You pressed Ctrl+C!')
sys.exit(0)
signal.signal(signal.SIGINT, signal_handler)
print('Press Ctrl+C')
forever = threading.Event()
forever.wait()
while True: continueembargo, espero que nunca lo hagas . (En ese estilo, while True: passsería más ordenado, de todos modos.) Eso sería un desperdicio; intente algo como while True: time.sleep(60 * 60 * 24)(dormir un día a la vez es una cifra completamente arbitraria).
time(como debería), no olvide import time:)
Si todo lo que desea es no mostrar el rastreo, haga su código así:
## all your app logic here
def main():
## whatever your app does.
if __name__ == "__main__":
try:
main()
except KeyboardInterrupt:
# do nothing here
pass
(Sí, sé que esto no responde directamente a la pregunta, pero no está realmente claro por qué es objetable necesitar un bloque try / except; tal vez esto lo haga menos molesto para el OP)
signal.signal( signal.SIGINT, lambda s, f : sys.exit(0))siempre lo hace.
Una alternativa para configurar su propio controlador de señales es usar un administrador de contexto para detectar la excepción e ignorarla:
>>> 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
...
>>>
Esto elimina el bloque try- exceptconservando alguna mención explícita de lo que está sucediendo.
Esto también le permite ignorar la interrupción solo en algunas partes de su código sin tener que configurar y restablecer nuevamente los controladores de señal cada vez.
Sé que esta es una pregunta antigua, pero vine aquí primero y luego descubrí el atexitmódulo. Todavía no conozco su historial multiplataforma o una lista completa de advertencias, pero hasta ahora es exactamente lo que estaba buscando al tratar de manejar post-KeyboardInterrupt limpieza en Linux. Solo quería incluir otra forma de abordar el problema.
Quiero hacer una limpieza posterior a la salida en el contexto de las operaciones de Fabric, por lo que envolver todo en try/ excepttampoco era una opción para mí. me siento comoatexit puede encajar bien en una situación así, en la que su código no está en el nivel superior de flujo de control.
atexit es muy capaz y legible desde el primer momento, por ejemplo:
import atexit
def goodbye():
print "You are now leaving the Python sector."
atexit.register(goodbye)
También puede usarlo como decorador (a partir de 2.6; este ejemplo es de los documentos):
import atexit
@atexit.register
def goodbye():
print "You are now leaving the Python sector."
Si quisiera hacerlo específico para KeyboardInterrupt solo , la respuesta de otra persona a esta pregunta probablemente sea mejor.
Pero tenga en cuenta que el atexitmódulo tiene solo ~ 70 líneas de código y no sería difícil crear una versión similar que trate las excepciones de manera diferente, por ejemplo, pasando las excepciones como argumentos a las funciones de devolución de llamada. (La limitación de atexiteso garantizaría una versión modificada: actualmente no puedo concebir una forma de que las funciones de devolución de llamada de salida conozcan las excepciones;atexit controlador detecta la excepción, llama a su devolución de llamada y luego vuelve a generar esa excepción. Pero podría hacerlo de otra manera).
Para obtener más información, consulte:
atexitPuede evitar la impresión de un seguimiento de pila para KeyboardInterrupt, sin try: ... except KeyboardInterrupt: pass(la solución más obvia y probablemente "mejor", pero ya la sabe y pidió algo más) reemplazando sys.excepthook. Algo como
def custom_excepthook(type, value, traceback):
if type is KeyboardInterrupt:
return # do nothing
else:
sys.__excepthook__(type, value, traceback)
Probé las soluciones sugeridas por todos, pero tuve que improvisar el código para que funcionara. A continuación está mi código improvisado:
import signal
import sys
import time
def signal_handler(signal, frame):
print('You pressed Ctrl+C!')
print(signal) # Value is 2 for CTRL + C
print(frame) # Where your execution of program is at moment - the Line Number
sys.exit(0)
#Assign Handler Function
signal.signal(signal.SIGINT, signal_handler)
# Simple Time Loop of 5 Seconds
secondsCount = 5
print('Press Ctrl+C in next '+str(secondsCount))
timeLoopRun = True
while timeLoopRun:
time.sleep(1)
if secondsCount < 1:
timeLoopRun = False
print('Closing in '+ str(secondsCount)+ ' seconds')
secondsCount = secondsCount - 1