在python中按CTRL + C时如何优雅地终止循环

发布于 2021-01-29 17:01:08

我是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
关注者
0
被浏览
171
1 个回答
  • 面试哥
    面试哥 2021-01-29
    为面试而生,有面试问题,就找面试哥。

    我只使用一个异常处理程序,它将捕获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()
    


知识点
面圈网VIP题库

面圈网VIP题库全新上线,海量真题题库资源。 90大类考试,超10万份考试真题开放下载啦

去下载看看