Existe-t-il un moyen dans Python) de capturer l'événement KeyboardInterrupt
sans placer tout le code dans une instruction try
-except
?
Je veux quitter proprement sans laisser de trace si l'utilisateur appuie sur Ctrl+C.
Oui, vous pouvez installer un gestionnaire d'interruptions à l'aide du module signal et attendre indéfiniment à l'aide de threading.Event :
import signal
import sys
import time
import threading
def signal_handler(signal, frame):
print('You pressed Ctrl+C!')
sys.exit(0)
signal.signal(signal.SIGINT, signal_handler)
print('Press Ctrl+C')
forever = threading.Event()
forever.wait()
Si tout ce que vous voulez est de ne pas afficher la trace, faites votre code comme ceci:
## all your app logic here
def main():
## whatever your app does.
if __== "__main__":
try:
main()
except KeyboardInterrupt:
# do nothing here
pass
(Oui, je sais que cela ne répond pas directement à la question, mais on ne comprend pas très bien pourquoi le blocage try/except est désagréable - cela le rend peut-être moins gênant pour l'OP)
Une alternative à la définition de votre propre gestionnaire de signal consiste à utiliser un gestionnaire de contexte pour intercepter l'exception et l'ignorer:
>>> class CleanExit(object):
... def __enter__(self):
... return self
... def __exit__(self, exc_type, exc_value, exc_tb):
... if exc_type is KeyboardInterrupt:
... return True
... return exc_type is None
...
>>> with CleanExit():
... input() #just to test it
...
>>>
Cela supprime le bloc try
-except
tout en préservant une mention explicite de ce qui se passe.
Cela vous permet également d'ignorer l'interruption uniquement dans certaines parties de votre code sans avoir à définir et à réinitialiser à nouveau les gestionnaires de signaux à chaque fois.
Je sais que c’est une vieille question, mais j’y suis arrivé en premier, puis j’ai découvert le module atexit
. Je ne connais pas encore ses antécédents multiplates-formes ni la liste complète des mises en garde, mais jusqu'à présent, c'est exactement ce que je cherchais pour tenter de gérer le nettoyage post -KeyboardInterrupt
sous Linux. Je voulais juste jeter une autre façon d'aborder le problème.
Je souhaite effectuer un nettoyage post-sortie dans le contexte des opérations Fabric, aussi, tout encapsuler dans try
/except
n'était pas une option pour moi non plus. Je pense que atexit
peut être un bon choix dans une telle situation, où votre code n'est pas au plus haut niveau du flux de contrôle.
atexit
est très performant et lisible, par exemple:
import atexit
def goodbye():
print "You are now leaving the Python sector."
atexit.register(goodbye)
Vous pouvez également l'utiliser comme décorateur (à partir de la version 2.6; cet exemple provient de la documentation):
import atexit
@atexit.register
def goodbye():
print "You are now leaving the Python sector."
Si vous voulez le rendre spécifique à KeyboardInterrupt
uniquement, la réponse d'une autre personne à cette question est probablement meilleure.
Notez cependant que le module atexit
ne contient que ~ 70 lignes de code et qu'il ne serait pas difficile de créer une version similaire qui traite les exceptions différemment, par exemple en transmettant les exceptions en tant qu'arguments aux fonctions de rappel. (La limitation de atexit
qui justifierait une version modifiée: actuellement, je ne peux concevoir un moyen de connaître les exceptions pour les fonctions exit-callback; le gestionnaire atexit
intercepte l'exception , appelle votre/vos rappel (s), puis relance cette exception, mais vous pouvez le faire différemment.)
Pour plus d'informations, voir:
atexit
Vous pouvez empêcher l’impression d’une trace de pile pour KeyboardInterrupt
, sans try: ... except KeyboardInterrupt: pass
_ (la solution la plus évidente et probablement la "meilleure", mais vous la connaissez déjà et avez demandé autre chose) en remplaçant sys.excepthook
. Quelque chose comme
def custom_excepthook(type, value, traceback):
if type is KeyboardInterrupt:
return # do nothing
else:
sys.__excepthook__(type, value, traceback)