Ich arbeite an einem Python-Skript, das mehrere Prozesse und Datenbankverbindungen startet. Hin und wieder möchte ich das Skript mit einem Ctrl+ C-Signal beenden und möchte eine Bereinigung durchführen.
In Perl würde ich Folgendes tun:
$SIG{'INT'} = 'exit_gracefully';
sub exit_gracefully {
print "Caught ^C \n";
exit (0);
}
Wie mache ich das Analogon dazu in Python?
./program.py > output.log
. Wenn Sie Strg-C drücken, soll Ihr Programm ordnungsgemäß beendet werden, indem protokolliert wird, dass alle Datendateien gelöscht und als sauber markiert wurden, um zu bestätigen, dass sie in einem bekanntermaßen guten Zustand verbleiben. Strg-C sendet jedoch SIGINT an alle Prozesse in einer Pipeline, sodass die Shell möglicherweise STDOUT (jetzt "output.log") schließt, bevor program.py den Druck des endgültigen Protokolls beendet. Python beschwert sich: "Schließen fehlgeschlagen im Dateiobjekt-Destruktor: Fehler in sys.excepthook:".Sie können es wie jede andere Ausnahme (KeyboardInterrupt) behandeln. Erstellen Sie eine neue Datei und führen Sie sie mit dem folgenden Inhalt aus Ihrer Shell aus, um zu sehen, was ich meine:
quelle
signal.signal(signal.SIGINT, signal.default_int_handler)
oder Sie werden scheitern, da KeyboardInterrupt nicht in jeder Situation ausgelöst wird, in der es ausgelöst werden sollte! Details finden Sie hier .Und als Kontextmanager:
Benutzen:
Verschachtelte Handler:
Von hier aus: https://gist.github.com/2907502
quelle
StopIteration
, um die innerste Schleife zu durchbrechen, wenn eine Strg-C gedrückt wird, oder?Sie können CTRL+ behandeln, Cindem Sie die
KeyboardInterrupt
Ausnahme abfangen . Sie können jeden Bereinigungscode im Ausnahmebehandler implementieren.quelle
Aus Pythons Dokumentation :
quelle
Noch ein Ausschnitt
Wird
main
als Hauptfunktion undexit_gracefully
als CTRL+ cHandler bezeichnetquelle
Ich habe den Code von @udi angepasst, um mehrere Signale zu unterstützen (nichts Besonderes):
Dieser Code unterstützt den Tastatur-Interrupt-Aufruf (
SIGINT
) und denSIGTERM
(kill <process>
)quelle
Im Gegensatz zu Matt Js Antwort verwende ich ein einfaches Objekt. Dies gibt mir die Möglichkeit, diesen Handler auf alle Threads zu analysieren, die gestoppt werden müssen.
Anderswo
quelle
time.sleep()
statt einer Besetztschleife eine Variable ausführen.Sie können die Funktionen in Pythons integriertem Signalmodul verwenden , um Signalhandler in Python einzurichten. Insbesondere wird die
signal.signal(signalnum, handler)
Funktion verwendet, um diehandler
Funktion für das Signal zu registrierensignalnum
.quelle
danke für vorhandene Antworten, aber hinzugefügt
signal.getsignal()
quelle
Wenn Sie sicherstellen möchten, dass Ihr Bereinigungsprozess abgeschlossen ist, würde ich die Antwort von Matt J mit einem SIG_IGN ergänzen, damit weitere
SIGINT
ignoriert werden, wodurch verhindert wird, dass Ihre Bereinigung unterbrochen wird.quelle
Persönlich konnte ich try / außer KeyboardInterrupt nicht verwenden, da ich den IPC-Modus (Standard Socket) verwendet habe, der blockiert. So wurde der SIGINT aufgerufen, kam aber erst nach Empfang von Daten auf dem Socket.
Das Einstellen eines Signalhandlers verhält sich genauso.
Dies funktioniert jedoch nur für ein tatsächliches Terminal. Andere Startumgebungen akzeptieren möglicherweise nicht Ctrl+C oder verarbeiten das Signal vorab.
Außerdem gibt es in Python "Ausnahmen" und "BaseExceptions", die sich in dem Sinne unterscheiden, dass der Interpreter sich selbst sauber beenden muss, sodass einige Ausnahmen eine höhere Priorität haben als andere (Ausnahmen werden von BaseException abgeleitet).
quelle