Python: Catch Ctrl-C comando. Preguntar “realmente quiero salir (y / n)”, reanudar la ejecución si no hay

Tengo un progtwig que puede tener una ejecución larga. En el módulo principal tengo lo siguiente:

import signal def run_program() ...time consuming execution... def Exit_gracefully(signal, frame): ... log exiting information ... ... close any open files ... sys.exit(0) if __name__ == '__main__': signal.signal(signal.SIGINT, Exit_gracefully) run_program() 

Esto funciona bien, pero me gustaría tener la posibilidad de pausar la ejecución al capturar SIGINT, preguntarle al usuario si realmente desea salir, y continuar donde lo dejé en run_program () si deciden que no quieren salir.

La única forma en que puedo pensar en hacer esto es ejecutar el progtwig en un subproceso separado, manteniendo el subproceso principal esperando y listo para capturar a SIGINT. Si el usuario desea salir del hilo principal, puede realizar una limpieza y eliminar el hilo secundario.

¿Hay alguna forma más simple?

Los manejadores de señales de python no parecen ser manejadores de señales reales; es decir, ocurren después del hecho, en el flujo normal y después de que el controlador C ya haya regresado. Por lo tanto, intentarías poner tu lógica de salida en el controlador de señales. Como el manejador de señales se ejecuta en el hilo principal, también bloqueará la ejecución allí.

Algo así parece funcionar bien.

 import signal import time import sys def run_program(): while True: time.sleep(1) print("a") def exit_gracefully(signum, frame): # restre the original signal handler as otherwise evil things will happen # in raw_input when CTRL+C is pressed, and our signal handler is not re-entrant signal.signal(signal.SIGINT, original_sigint) try: if raw_input("\nReally quit? (y/n)> ").lower().startswith('y'): sys.exit(1) except KeyboardInterrupt: print("Ok ok, quitting") sys.exit(1) # restre the exit gracefully handler here signal.signal(signal.SIGINT, exit_gracefully) if __name__ == '__main__': # store the original SIGINT handler original_sigint = signal.getsignal(signal.SIGINT) signal.signal(signal.SIGINT, exit_gracefully) run_program() 

El código restaura el controlador de señal original durante la duración de raw_input ; raw_input sí no se puede volver a arrastrar, y volver a entrar llevará a RuntimeError: can't re-enter readline en la time.sleep de time.sleep que se time.sleep desde time.sleep que es algo que no queremos ya que es más difícil de atrapar que KeyboardInterrupt . Por el contrario, permitimos que 2 Ctrl-C consecutivas aumenten KeyboardInterrupt .