Capturez keyboardinterrupt en Python sans essayer-sauf

y a - t-il un moyen en Python de capturer KeyboardInterrupt sans mettre tout le code dans une déclaration try - except ?

je veux sortir proprement sans trace si l'utilisateur appuie sur Ctrl + C .

92
demandé sur Benyamin Jafari 2010-11-17 17:24:51

5 réponses

Oui, vous pouvez installer un gestionnaire d'interruption en utilisant le module signal , et attendre pour toujours en utilisant un filetage .Événement :

import signal
import sys
import time

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()
132
répondu Johan Kotlinski 2018-04-11 22:03:45

si tout ce que vous voulez est de ne pas montrer le traceback, faites votre code comme ceci:

## all your app logic here
def main():
   ## whatever your app does.


if __name__ == "__main__":
   try:
      main()
   except KeyboardInterrupt:
      # do nothing here
      pass

(Oui, je sais que cela ne répond pas directement à la question, mais il n'est pas vraiment clair pourquoi le fait d'avoir besoin d'un essai/sauf un bloc est répréhensible -- peut-être que cela le rend moins ennuyeux pour L'OP)

30
répondu bgporter 2010-11-17 14:32:56

une alternative à la mise en place de votre propre gestionnaire de signal est d'utiliser un gestionnaire de contexte pour saisir 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 seulement dans certaines parties de votre code sans avoir à régler et réinitialiser à nouveau les gestionnaires de signal à chaque fois.

24
répondu Bakuriu 2016-07-03 14:34:25

je sais que c'est une vieille question mais je suis venu ici d'abord et puis j'ai découvert le module atexit . Je ne suis pas encore au courant de son historique multiplateformes ou d'une liste complète de mises en garde, mais jusqu'à présent, c'est exactement ce que je cherchais en essayant de gérer le nettoyage post- KeyboardInterrupt sur Linux. Juste envie de le jeter dans une autre façon d'aborder le problème.

je veux faire le nettoyage après-sortie dans le contexte des opérations de tissu, donc envelopper tout dans try / except n'était pas une option pour moi non plus. Je pense que atexit peut être un bon ajustement dans une telle situation, où votre code n'est pas au niveau supérieur du flux de contrôle.

atexit est très capable et lisible de la boîte, 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 2.6; cet exemple est tiré du docs):

import atexit

@atexit.register
def goodbye():
    print "You are now leaving the Python sector."

si vous vouliez le rendre spécifique à KeyboardInterrupt seulement, la réponse d'une autre personne à cette question est probablement meilleure.

mais notez que le module atexit n'est qu'environ 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 passant les exceptions comme arguments aux fonctions de rappel. (La limitation de atexit qui justifierait une version modifiée: actuellement Je ne peux pas concevoir un moyen pour les fonctions exit-callback de connaître les exceptions; le gestionnaire atexit saisit l'exception, appelle votre(vos) rappel (s), puis relance cette exception. Mais tu pourrais faire ça différemment.)

pour plus d'informations voir:

5
répondu hangtwenty 2013-11-05 14:15:54

vous pouvez empêcher l'impression d'une trace de pile pour KeyboardInterrupt , sans try: ... except KeyboardInterrupt: pass (la solution la plus évidente et propablement "meilleure", mais vous le savez déjà et demandé quelque chose d'autre) 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)
4
répondu Richard 2015-08-15 21:18:19