Question Comment capturer SIGINT en Python?


Je travaille sur un script python qui démarre plusieurs processus et connexions de bases de données. De temps en temps, je veux tuer le script avec un Ctrl+C signal, 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 est-ce que je fais l'analogue de ceci en Python?


427
2017-07-10 22:49


origine


Réponses:


Enregistrez votre gestionnaire avec signal.signal comme ça:

#!/usr/bin/env python
import signal
import sys
def signal_handler(sig, frame):
        print('You pressed Ctrl+C!')
        sys.exit(0)
signal.signal(signal.SIGINT, signal_handler)
print('Press Ctrl+C')
signal.pause()

Code adapté de ici.

Plus de documentation sur signal peut être trouvé ici.


619
2017-07-10 22:52



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:

import time, sys

x = 1
while True:
    try:
        print x
        time.sleep(.3)
        x += 1
    except KeyboardInterrupt:
        print "Bye"
        sys.exit()

141
2017-07-10 22:54



Et en tant que gestionnaire de contexte:

import signal

class GracefulInterruptHandler(object):

    def __init__(self, sig=signal.SIGINT):
        self.sig = sig

    def __enter__(self):

        self.interrupted = False
        self.released = False

        self.original_handler = signal.getsignal(self.sig)

        def handler(signum, frame):
            self.release()
            self.interrupted = True

        signal.signal(self.sig, handler)

        return self

    def __exit__(self, type, value, tb):
        self.release()

    def release(self):

        if self.released:
            return False

        signal.signal(self.sig, self.original_handler)

        self.released = True

        return True

Utiliser:

with GracefulInterruptHandler() as h:
    for i in xrange(1000):
        print "..."
        time.sleep(1)
        if h.interrupted:
            print "interrupted!"
            time.sleep(2)
            break

Gestionnaires imbriqués:

with GracefulInterruptHandler() as h1:
    while True:
        print "(1)..."
        time.sleep(1)
        with GracefulInterruptHandler() as h2:
            while True:
                print "\t(2)..."
                time.sleep(1)
                if h2.interrupted:
                    print "\t(2) interrupted!"
                    time.sleep(2)
                    break
        if h1.interrupted:
            print "(1) interrupted!"
            time.sleep(2)
            break

D'ici: https://gist.github.com/2907502


53
2018-06-10 22:23



Vous pouvez gérer CTRL+C en attrapant le KeyboardInterrupt exception. Vous pouvez implémenter n'importe quel code de nettoyage dans le gestionnaire d'exceptions.


23
2017-07-10 22:52



De Python Documentation:

import signal
import time

def handler(signum, frame):
    print 'Here you go'

signal.signal(signal.SIGINT, handler)

time.sleep(10) # Press Ctrl+c here

18
2017-07-10 22:56



Encore un autre extrait

Référé main comme fonction principale et exit_gracefully comme le CTRL + c gestionnaire

if __name__ == '__main__':
    try:
        main()
    except KeyboardInterrupt:
        pass
    finally:
        exit_gracefully()

12
2017-08-15 15:00



J'ai adapté le code de @udi pour supporter plusieurs signaux (rien d'extraordinaire):

class GracefulInterruptHandler(object):
    def __init__(self, signals=(signal.SIGINT, signal.SIGTERM)):
        self.signals = signals
        self.original_handlers = {}

    def __enter__(self):
        self.interrupted = False
        self.released = False

        for sig in self.signals:
            self.original_handlers[sig] = signal.getsignal(sig)
            signal.signal(sig, self.handler)

        return self

    def handler(self, signum, frame):
        self.release()
        self.interrupted = True

    def __exit__(self, type, value, tb):
        self.release()

    def release(self):
        if self.released:
            return False

        for sig in self.signals:
            signal.signal(sig, self.original_handlers[sig])

        self.released = True
        return True

Ce code prend en charge l'appel d'interruption du clavier (SIGINT) et le SIGTERM (kill <process>)


6
2018-03-04 14:27



Vous pouvez utiliser les fonctions dans le built-in de Python module de signal configurer des gestionnaires de signaux en python. Plus précisément, le signal.signal(signalnum, handler) fonction est utilisée pour enregistrer le handler fonction pour le signal signalnum.


4
2017-07-10 22:54



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.

class SIGINT_handler():
    def __init__(self):
        self.SIGINT = False

    def signal_handler(self, signal, frame):
        print('You pressed Ctrl+C!')
        self.SIGINT = True


handler = SIGINT_handler()
signal.signal(signal.SIGINT, handler.signal_handler)

Autre part

while True:
    # task
    if handler.SIGINT:
        break

2
2018-05-04 15:52