Comment mettre fin à la boucle gracieusement lorsque CTRL+C a été pressé en python
Je suis un peu en python et je me retrouve avec le problème suivant.
J'ai un script qui traite les dossiers un par un et écrit le résultat dans des fichiers séparés selon le nom de fichier d'entrée. Parfois j'ai besoin de briser le script, mais je tiens à le laisser terminer le traitement actuel de fichier, puis de mettre fin (pour éviter les fichiers de résultats avec des informations incomplètes). Comment coder ce problème en python?
Voici ce que j'ai essayé.
a) Essayez-à l'exception du bloc
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()
De sortie:
Script started.
Processing file # 1 started... finished.
Processing file # 2 started... finished.
Processing file # 3 started... Bye
x= 3
Itération #3 n'est pas terminé normalement.
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()
De sortie:
Script started.
Processing file # 1 started... finished.
Processing file # 2 started... finished.
Processing file # 3 started...
Exiting by CTRL+C.
Itération #3 n'est pas terminé normalement.
UPD#1
@mguijarr , j'ai légèrement modifié le code comme ceci:
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()
La sortie est (testé à l'aide de "Python 2.7.6 :: Anaconda 2.0.0 (64-bit)" sur Win7-64 bits):
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
Dans ce cas itération #3 a effectivement été redémarré, ce qui semble étrange et n'est pas un comportement souhaité. Est-il possible de l'éviter?
J'ai enlevé les virgules dans "imprimer" des déclarations et a ajouté plus de choses à voir que l'itération est effectivement redémarré:
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()
et la sortie est:
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
OriginalL'auteur anandr | 2014-06-26
Vous devez vous connecter pour publier un commentaire.
Je voudrais simplement utiliser un gestionnaire d'exception, qui serait attraper
KeyboardInterrupt
etstore l'exception. Puis, au moment d'une itération est terminée, si une exception
est en attente je voudrais briser la boucle et de la relancer l'exception (pour laisser la normale exception
la manipulation d'une chance de se produire).
Cela fonctionne (testé avec Python 2.7):
EDIT: comme il a été repéré dans les commentaires, cette réponse n'est pas satisfaisante pour l'affiche originale, voici une solution à base de threads:
Vous êtes sûr que c'est redémarré? Je pense que l'exception est juste raté la sortie standard, car il est tamponné (supprimer le "," à la fin de vos instructions d'impression)
Semble comme il est vraiment. Voir mise à jour du code en question. Je suis aussi d'errance pourquoi il est comme ça.
Notez que vous appuyez sur Ctrl-C avant de
x
est incrémenté, puis vous commencez une autre boucle, puis tester la stockées exception et se briser. Notez également que si vous interrompez votre code par exception, vous ne pouvez pas il suffit de continuer le calcul précédent. Vous souhaitez faire retarder l'interrompre afin d'utiliser quelque chose comme le signal semble être le seul moyen.Il serait également plus naturel de jeter le fichier actuel sur Ctrl-C si vous ne voulez pas des résultats incomplets, plutôt que de l'attendre. Dans ce cas, vous n'avez besoin de rien de spécial. Viens de faire le nettoyage de fichier en cours après la capture de KeyboardInterrupt.
OriginalL'auteur mguijarr
Vous pouvez écrire un signal fonction de gestion des
appuyant sur Ctrl+c envoie un SIGINT interruption qui de sortie:
De son la sortie exacte copie de mon terminal. Je suis à l'aide de python 2.7.7 sur linux
Je ne sais pas comment ajouter des gros blocs de code de commentaire, donc j'ai mis à jour votre réponse à la de démontrer ce que je vois lorsque je l'exécute votre code.
OriginalL'auteur Ashoka Lella