Je travaille sur un script python qui démarre plusieurs processus et connexions à la base de données. De temps en temps, je veux tuer le script avec un signal Ctrl+ C, et je voudrais faire un peu de nettoyage.
En Perl, je ferais ceci:
$SIG{'INT'} = 'exit_gracefully';
sub exit_gracefully {
print "Caught ^C \n";
exit (0);
}
Comment puis-je faire l'analogue de cela en Python?
./program.py > output.log
. Lorsque vous appuyez sur Ctrl-C, vous souhaitez que votre programme se termine correctement en lui faisant enregistrer que tous les fichiers de données ont été vidés et marqués comme propres pour confirmer qu'ils sont laissés dans un bon état connu. Mais Ctrl-C envoie SIGINT à tous les processus d'un pipeline, donc le shell peut fermer STDOUT (maintenant "output.log") avant que program.py ne termine l'impression du journal final. Python se plaindra, "échec de fermeture dans le destructeur d'objets de fichier: erreur dans sys.excepthook:".Vous pouvez le traiter comme une exception (KeyboardInterrupt), comme n'importe quelle autre. Créez un nouveau fichier et exécutez-le à partir de votre shell avec le contenu suivant pour voir ce que je veux dire:
la source
signal.signal(signal.SIGINT, signal.default_int_handler)
ou vous allez échouer, car KeyboardInterrupt ne se déclenche pas dans toutes les situations où il doit se déclencher! Les détails sont ici .Et en tant que gestionnaire de contexte:
Utiliser:
Gestionnaires imbriqués:
À partir d'ici: https://gist.github.com/2907502
la source
StopIteration
pour rompre la boucle la plus intérieure lorsqu'un ctrl-C est pressé, non?Vous pouvez gérer CTRL+ Cen interceptant l'
KeyboardInterrupt
exception. Vous pouvez implémenter n'importe quel code de nettoyage dans le gestionnaire d'exceptions.la source
De la documentation de Python :
la source
Encore un autre extrait
Référé
main
comme fonction principale etexit_gracefully
comme gestionnaire CTRL+cla source
J'ai adapté le code de @udi pour supporter plusieurs signaux (rien d'extraordinaire):
Ce code prend en charge l'appel d'interruption clavier (
SIGINT
) etSIGTERM
(kill <process>
)la source
Contrairement à Matt J, sa réponse, j'utilise un objet simple. Cela me donne la possibilité d'analyser ce gestionnaire pour tous les threads qui doivent être arrêtés en sécurité.
Autre part
la source
time.sleep()
au lieu de faire une boucle occupée sur une variable.Vous pouvez utiliser les fonctions du module de signal intégré de Python pour configurer des gestionnaires de signal en python. Plus précisément, la
signal.signal(signalnum, handler)
fonction est utilisée pour enregistrer lahandler
fonction pour le signalsignalnum
.la source
merci pour les réponses existantes, mais ajouté
signal.getsignal()
la source
Si vous voulez vous assurer que votre processus de nettoyage se termine, j'ajouterais à la réponse de Matt J en utilisant un SIG_IGN afin que d'autres
SIGINT
soient ignorés, ce qui empêchera votre nettoyage d'être interrompu.la source
Personnellement, je ne pouvais pas utiliser try / except KeyboardInterrupt car j'utilisais le mode socket standard (IPC) qui bloque. Le SIGINT a donc été mis en file d'attente, mais n'est venu qu'après avoir reçu des données sur le socket.
La définition d'un gestionnaire de signaux se comporte de la même manière.
En revanche, cela ne fonctionne que pour un terminal réel. D'autres environnements de démarrage peuvent ne pas accepter Ctrl+ Cou pré-gérer le signal.
De plus, il existe des "Exceptions" et "BaseExceptions" en Python, qui diffèrent dans le sens où l'interpréteur doit se fermer proprement, donc certaines exceptions ont une priorité plus élevée que d'autres (les exceptions sont dérivées de BaseException)
la source