it-swarm.com.de

Wie erfasse ich SIGINT in Python?

Ich arbeite an einem Python-Skript, das mehrere Prozesse und Datenbankverbindungen startet. Hin und wieder möchte ich das Drehbuch mit einem töten Ctrl+C signalisieren, und ich möchte etwas aufräumen.

In Perl würde ich das machen:

$SIG{'INT'} = 'exit_gracefully';

sub exit_gracefully {
    print "Caught ^C \n";
    exit (0);
}

Wie mache ich das Analog dazu in Python?

477
James Thompson

Registrieren Sie Ihren Handler wie folgt mit signal.signal:

#!/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 angepasst von hier .

Weitere Dokumentation zu signal finden Sie hier .

667
Matt J

Sie können es wie eine Ausnahme (KeyboardInterrupt) behandeln, wie alle anderen. Erstellen Sie eine neue Datei und führen Sie sie in Ihrer Shell mit folgendem Inhalt aus, um zu sehen, was ich meine:

import time, sys

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

Und als Kontextmanager:

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

Benutzen:

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

Verschachtelte Handler:

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

Von hier: https://Gist.github.com/2907502

57
Udi

Sie können damit umgehen CTRL+C indem Sie die Ausnahme KeyboardInterrupt abfangen. Sie können jeden Bereinigungscode im Ausnahmehandler implementieren.

26
Jay Conrod

Aus Pythons Dokumentation :

import signal
import time

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

signal.signal(signal.SIGINT, handler)

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

Noch ein Ausschnitt

main als Hauptfunktion und exit_gracefully als CTRL + c Handler

if __== '__main__':
    try:
        main()
    except KeyboardInterrupt:
        pass
    finally:
        exit_gracefully()
13
Jossef Harush

Ich habe den Code von @udi so angepasst, dass er mehrere Signale unterstützt (nichts Besonderes):

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

Dieser Code unterstützt den Tastatur-Interrupt-Aufruf (SIGINT) und die SIGTERM (kill <process>).

7
Cyril N.

Sie können die Funktionen in Pythons eingebautem signal module verwenden, um Signalhandler in Python einzurichten. Insbesondere wird die Funktion signal.signal(signalnum, handler) verwendet, um die Funktion handler für das Signal signalnum zu registrieren.

4

Im Gegensatz zu Matt J seiner Antwort verwende ich ein einfaches Objekt. Dies gibt mir die Möglichkeit, diesen Handler zu allen Threads zu parsen, die in einer Sicherheitsstufe angehalten werden müssen.

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)

Anderswo

while True:
    # task
    if handler.SIGINT:
        break
3
Thomas Devoogdt

danke für vorhandene Antworten, aber hinzugefügt signal.getsignal()

import signal

# store default handler of signal.SIGINT
default_handler = signal.getsignal(signal.SIGINT)
catch_count = 0

def handler(signum, frame):
    global default_handler, catch_count
    catch_count += 1
    print ('wait:', catch_count)
    if catch_count > 3:
        # recover handler for signal.SIGINT
        signal.signal(signal.SIGINT, default_handler)
        print('expecting KeyboardInterrupt')

signal.signal(signal.SIGINT, handler)
print('Press Ctrl+c here')

while True:
    pass
0
gsw945

Ich persönlich konnte try/außer KeyboardInterrupt nicht verwenden, da ich den Standard-Socket-Modus (IPC) verwendete, der blockiert. Der SIGINT wurde also vorgespielt, kam aber erst nach Erhalt der Daten auf dem Sockel.

Das Festlegen eines Signalhandlers verhält sich genauso.

Andererseits funktioniert dies nur für ein tatsächliches Terminal. Andere Startumgebungen akzeptieren möglicherweise nicht Strg + C oder behandeln das Signal nicht vorab.

Außerdem gibt es in Python "Exceptions" und "BaseExceptions", die sich in der Hinsicht unterscheiden, dass der Interpreter selbst sauber beendet werden muss. Daher haben einige Ausnahmen eine höhere Priorität als andere.

0
Agnes K. Cathex