Attraper KeyboardInterrupt en Python lors de l'arrêt du programme

j'écris un utilitaire de ligne de commande en Python qui, puisqu'il s'agit de code de production, devrait pouvoir s'arrêter proprement sans jeter un tas de choses (codes d'erreur, traces de pile, etc.) à l'écran. Cela signifie que j'ai besoin d'attraper les interruptions de clavier.

j'ai essayé d'utiliser à la fois un bloc d'essai comme:

if __name__ == '__main__':
    try:
        main()
    except KeyboardInterrupt:
        print 'Interrupted'
        sys.exit(0)

et attraper le signal lui-même (comme dans ce post ):

import signal
import sys

def sigint_handler(signal, frame):
    print 'Interrupted'
    sys.exit(0)
signal.signal(signal.SIGINT, sigint_handler)

les deux méthodes semblent fonctionner assez bien pendant le fonctionnement normal. Cependant, si l'interruption se produit pendant le code de nettoyage à la fin de L'application, Python semble toujours imprimer quelque chose à l'écran. Attraper l'interruption donne

^CInterrupted
Exception KeyboardInterrupt in <bound method MyClass.__del__ of <path.to.MyClass object at 0x802852b90>> ignored

alors que la manipulation du signal donne soit

^CInterrupted
Exception SystemExit: 0 in <Finalize object, dead> ignored

ou

^CInterrupted
Exception SystemExit: 0 in <bound method MyClass.__del__ of <path.to.MyClass object at 0x802854a90>> ignored

non seulement ces erreurs sont laides, mais elles ne sont pas très utiles (surtout pour un utilisateur final sans le code source)!

le code de nettoyage pour cette application est assez grand, donc il y a une bonne chance que ce problème sera touché par de vrais utilisateurs. Y a-t-il un moyen d'attraper ou de bloquer cette sortie, ou est-ce juste quelque chose que je vais devoir gérer?

41
demandé sur Community 2014-01-14 22:17:03

2 réponses

check-out ce thread , il contient des informations utiles sur les sorties et les tracebacks.

si vous êtes plus intéressé à simplement tuer le programme, Essayez quelque chose comme ceci (cela enlèvera les jambes sous le code de nettoyage aussi bien):

if __name__ == '__main__':
    try:
        main()
    except KeyboardInterrupt:
        print('Interrupted')
        try:
            sys.exit(0)
        except SystemExit:
            os._exit(0)
62
répondu Dan Hogan 2018-07-24 12:12:47

vous pouvez ignorer les SIGINTs après le début de l'arrêt en appelant signal.signal(signal.SIGINT, signal.SIG_IGN) avant de commencer votre code de nettoyage.

5
répondu Dan Getz 2014-01-15 15:38:19