在python中按CTRL + C时如何优雅地终止循环
我是python的新手,并且遇到了以下问题。我有一个脚本,可以逐个处理文件,并根据输入的文件名将输出写入单独的文件中。有时我需要破坏脚本,但是我想让它完成对当前文件的处理,然后终止(以避免结果文件中的信息不完整)。如何在python中编码此行为?
这是我尝试过的。
a)尝试除外块
x = 1
print "Script started."
while True:
try:
print "Processing file #",x,"started...",
# do something time-cosnuming
time.sleep(1)
x += 1
print " finished."
except KeyboardInterrupt:
print "Bye"
print "x=",x
sys.exit()
sys.exit()
输出:
Script started.
Processing file # 1 started... finished.
Processing file # 2 started... finished.
Processing file # 3 started... Bye
x= 3
迭代3无法正常完成。
b)sys.excepthook
OriginalExceptHook = sys.excepthook
def NewExceptHook(type, value, traceback):
global Terminator
Terminator = True
if type == KeyboardInterrupt:
#exit("\nExiting by CTRL+C.") # this line was here originally
print("\n\nExiting by CTRL+C.\n\n")
else:
OriginalExceptHook(type, value, traceback)
sys.excepthook = NewExceptHook
global Terminator
Terminator = False
x = 1
while True:
print "Processing file #",x,"started...",
# do something time-cosnuming
time.sleep(1)
x += 1
print " finished."
if Terminator:
print "I'll be back!"
break
print "Bye"
print "x=",x
sys.exit()
输出:
Script started.
Processing file # 1 started... finished.
Processing file # 2 started... finished.
Processing file # 3 started...
Exiting by CTRL+C.
迭代3无法正常完成。
UPD#1
@mguijarr,我对代码进行了如下修改:
import time, sys
x = 1
print "Script started."
stored_exception=None
while True:
try:
print "Processing file #",x,"started...",
# do something time-cosnuming
time.sleep(1)
print "Processing file #",x,"part two...",
time.sleep(1)
print " finished."
if stored_exception:
break
x += 1
except KeyboardInterrupt:
print "[CTRL+C detected]",
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()
输出(在Win7-64位上使用“ Python 2.7.6 :: Anaconda 2.0.0(64位)”进行了测试):
Script started.
Processing file # 1 started... Processing file # 1 part two... finished.
Processing file # 2 started... Processing file # 2 part two... finished.
Processing file # 3 started... [CTRL+C detected] Processing file # 3 started... Processing file # 3 part two... finished.
Bye
x= 3
Traceback (most recent call last):
File "test2.py", line 12, in <module>
time.sleep(1)
KeyboardInterrupt
在这种情况下,迭代#3已有效地重新启动,这看起来很奇怪,并且不是理想的行为。有可能避免这种情况吗?
我在“打印”语句中删除了逗号,并添加了更多内容以查看迭代实际上已重新开始:
import time, sys
x = 1
y = 0
print "Script started."
stored_exception=None
while True:
try:
y=x*1000
y+=1
print "Processing file #",x,y,"started..."
y+=1
# do something time-cosnuming
y+=1
time.sleep(1)
y+=1
print "Processing file #",x,y,"part two..."
y+=1
time.sleep(1)
y+=1
print " finished.",x,y
y+=1
if stored_exception:
break
y+=1
x += 1
y+=1
except KeyboardInterrupt:
print "[CTRL+C detected]",
stored_exception=sys.exc_info()
print "Bye"
print "x=",x
print "y=",y
if stored_exception:
raise stored_exception[0], stored_exception[1], stored_exception[2]
sys.exit()
输出为:
Script started.
Processing file # 1 1001 started...
Processing file # 1 1004 part two...
finished. 1 1006
Processing file # 2 2001 started...
Processing file # 2 2004 part two...
[CTRL+C detected] Processing file # 2 2001 started...
Processing file # 2 2004 part two...
finished. 2 2006
Bye
x= 2
y= 2007
Traceback (most recent call last):
File "test2.py", line 20, in <module>
time.sleep(1)
KeyboardInterrupt
-
我只使用一个异常处理程序,它将捕获
KeyboardInterrupt
并存储异常。然后,在迭代完成的那一刻,如果有一个异常待处理,我将中断循环并重新引发该异常(以使正常的异常处理有机会发生)。这有效(已在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()
编辑: 由于已在评论中发现,此答案对于原始海报不令人满意,这是基于线程的解决方案:
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()