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: continue
embargo, espero que nunca lo hagas . (En ese estilo, while True: pass
serí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
- except
conservando 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 atexit
mó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
/ except
tampoco 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 atexit
mó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 atexit
eso 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:
atexit
Puede 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