在python中按CTRL + C时如何优雅地终止循环 [英] How to terminate loop gracefully when CTRL+C was pressed in python

查看:256
本文介绍了在python中按CTRL + C时如何优雅地终止循环的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是python的新手,但我遇到了以下问题. 我有一个脚本,可以逐个处理文件,并根据输入文件名将输出写到单独的文件中.有时我需要破坏脚本,但是我想让它完成对当前文件的处理,然后终止(以避免结果文件中包含不完整的信息).如何用python编码这种行为?

I'm rather new to python and I'm stuck with the following problem. I have a script that processes files one-by-one and writes output into separate files according to input file name. Sometimes I need to break the script, but I'd like to let it finish processing current file and then terminate (to avoid result files with incomplete information). How to code this behavior in 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

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不能正常完成.

@mguijarr,我对代码进行了如下修改:

@mguijarr , I slightly modified code like this:

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位)"进行了测试):

The output is (tested using "Python 2.7.6 :: Anaconda 2.0.0 (64-bit)" on Win7-64bit):

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次迭代已有效地重新启动,这看起来很奇怪并且不是理想的行为.有可能避免这种情况吗?

In this case iteration #3 was effectively restarted, which looks odd and is not a desired behavior. Is it possible to avoid this?

我删除了'print'语句中的逗号,并添加了更多内容以查看迭代实际上已重新开始:

I removed commas in 'print' statements and added more stuff to see that iteration is actually restarted:

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和 存储异常.然后,如果有异常,则此刻迭代完成 等待中,我会打破循环并重新引发异常(让普通异常 处理机会).

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).

这有效(已在Python 2.7上测试):

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()

,因为它已在评论中发现,对于原始海报来说,此答案不令人满意,这是基于线程的解决方案:

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()

这篇关于在python中按CTRL + C时如何优雅地终止循环的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆