How to terminate loop gracefully when CTRL+C was pressed in python
I would simply use an exception handler, which would catch KeyboardInterrupt
and
store the exception. Then, at the moment an iteration is finished, if an exception
is pending I would break the loop and re-raise the exception (to let normal exception
handling a chance to happen).
This works (tested with Python 2.7):
x = 1
print "Script started."
stored_exception=None
while True:
try:
print "Processing file #",x,"started...",
# do something time-cosnuming
time.sleep(1)
print " finished."
if stored_exception:
break
x += 1
except KeyboardInterrupt:
stored_exception=sys.exc_info()
print "Bye"
print "x=",x
if stored_exception:
raise stored_exception[0], stored_exception[1], stored_exception[2]
sys.exit()
EDIT: as it has been spotted in the comments, this answer is not satisfying for the original poster, here is a solution based on threads:
import time
import sys
import threading
print "Script started."
class MyProcessingThread(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
def run(self):
print "Processing file #",x,"started...",
# do something time-cosnuming
time.sleep(1)
print " finished."
for x in range(1,4):
task = MyProcessingThread()
task.start()
try:
task.join()
except KeyboardInterrupt:
break
print "Bye"
print "x=",x
sys.exit()
You can write a signal handling function
import signal,sys,time
terminate = False
def signal_handling(signum,frame):
global terminate
terminate = True
signal.signal(signal.SIGINT,signal_handling)
x=1
while True:
print "Processing file #",x,"started..."
time.sleep(1)
x+=1
if terminate:
print "I'll be back"
break
print "bye"
print x
pressing Ctrl+c sends a SIGINT interrupt which would output:
Processing file # 1 started...
Processing file # 2 started...
^CI'll be back
bye
3
I feel that creating a class with a state that handles user exceptions is a bit more elegant since I don't have to mess with global variables that don't work across different modules
import signal
import time
class GracefulExiter():
def __init__(self):
self.state = False
signal.signal(signal.SIGINT, self.change_state)
def change_state(self, signum, frame):
print("exit flag set to True (repeat to exit now)")
signal.signal(signal.SIGINT, signal.SIG_DFL)
self.state = True
def exit(self):
return self.state
x = 1
flag = GracefulExiter()
while True:
print("Processing file #",x,"started...")
time.sleep(1)
x+=1
print(" finished.")
if flag.exit():
break