How to stop an infinite loop safely in Python?
What you need to do is catch the interrupt, set a flag saying you were interrupted but then continue working until it's time to check the flag (at the end of each loop). Because python's try-except construct will abandon the current run of the loop, you need to set up a proper signal handler; it'll handle the interrupt but then let python continue where it left off. Here's how:
import signalimport time # For the demo onlydef signal_handler(signal, frame): global interrupted interrupted = Truesignal.signal(signal.SIGINT, signal_handler)interrupted = Falsewhile True: print("Working hard...") time.sleep(3) print("All done!") if interrupted: print("Gotta go") break
Notes:
Use this from the command line. In the IDLE console, it'll trample on IDLE's own interrupt handling.
A better solution would be to "block" KeyboardInterrupt for the duration of the loop, and unblock it when it's time to poll for interrupts. This is a feature of some Unix flavors but not all, hence python does not support it (see the third "General rule")
The OP wants to do this inside a class. But the interrupt function is invoked by the signal handling system, with two arguments: The signal number and a pointer to the stack frame-- no place for a
self
argument giving access to the class object. Hence the simplest way to set a flag is to use a global variable. You can rig a pointer to the local context by using closures (i.e., define the signal handler dynamically in__init__()
, but frankly I wouldn't bother unless a global is out of the question due to multi-threading or whatever.
Caveat: If your process is in the middle of a system call, handling an signal may interrupt the system call. So this may not be safe for all applications. Safer alternatives would be (a) Instead of relying on signals, use a non-blocking read at the end of each loop iteration (and type input instead of hitting ^C); (b) use threads or interprocess communication to isolate the worker from the signal handling; or (c) do the work of implementing real signal blocking, if you are on an OS that has it. All of them are OS-dependent to some extent, so I'll leave it at that.
the below logic will help you do this,
import signalimport sysimport timerun = Truedef signal_handler(signal, frame): global run print "exiting" run = Falsesignal.signal(signal.SIGINT, signal_handler)while run: print "hi" time.sleep(1) # do anything print "bye"
while running this, try pressing CTRL+C
I hope below code would help you:
#!/bin/pythonimport sysimport timeimport signaldef cb_sigint_handler(signum, stack): global is_interrupted print "SIGINT received" is_interrupted = Trueif __name__ == "__main__": is_interrupted = False signal.signal(signal.SIGINT, cb_sigint_handler) while(1): # do stuff here print "processing..." time.sleep(3) if is_interrupted: print "Exiting.." # do clean up sys.exit(0)