risposta-alla-domanda-sullo-sviluppo-web-bd.com

Come posso acquisire SIGINT in Python?

Sto lavorando su uno script python che avvia diversi processi e connessioni al database. Ogni tanto voglio uccidere la sceneggiatura con a Ctrl+C segnale, e mi piacerebbe fare un po 'di pulizia.

In Perl farei questo:

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

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

Come faccio a fare l'analogo di questo in Python?

477
James Thompson

Registra il tuo gestore con signal.signal in questo modo:

#!/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()

Codice adattato da qui .

Più documentazione su signal può essere trovata qui .

667
Matt J

Puoi trattarlo come un'eccezione (KeyboardInterrupt), come qualsiasi altra. Crea un nuovo file ed eseguilo dalla tua shell con i seguenti contenuti per vedere cosa intendo:

import time, sys

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

E come gestore del contesto:

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

Usare:

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

Gestori annidati:

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

Da qui: https://Gist.github.com/2907502

57
Udi

Puoi gestire CTRL+C catturando l'eccezione KeyboardInterrupt. È possibile implementare qualsiasi codice di pulizia nel gestore di eccezioni.

26
Jay Conrod

Da Python's 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
19
sunqiang

Ancora un altro frammento

Riferito main come funzione principale e exit_gracefully come CTRL + c gestore

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

Ho adattato il codice da @udi per supportare più segnali (niente di speciale):

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

Questo codice supporta la chiamata interrupt di tastiera (SIGINT) e SIGTERM (kill <process>)

7
Cyril N.

Puoi usare le funzioni nel modulo di segnale integrato di Python per impostare i gestori di segnale in python. In particolare, la funzione signal.signal(signalnum, handler) viene utilizzata per registrare la funzione handler per il segnale signalnum.

4
Brandon E Taylor

In contrasto con Matt J la sua risposta, io uso un oggetto semplice. Questo mi dà la possibilità di analizzare questo gestore per tutti i thread che devono essere fermati in sicurezza.

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)

Altrove

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

grazie per le risposte esistenti, ma aggiunto 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

Personalmente, non ho potuto usare try/except KeyboardInterrupt perché stavo usando la modalità socket standard (IPC) che sta bloccando. Quindi il SIGINT è stato cueued, ma è arrivato solo dopo aver ricevuto i dati sul socket.

L'impostazione di un gestore di segnale si comporta allo stesso modo.

D'altra parte, questo funziona solo per un vero terminale. Altri ambienti di partenza potrebbero non accettare Ctrl + C o pre-gestire il segnale.

Inoltre, in Python esistono "Eccezioni" e "BaseExceptions", che differiscono nel senso che l'interprete deve uscire in modo pulito, quindi alcune eccezioni hanno una priorità più alta di altre (Eccezioni derivate da BaseException)

0
Agnes K. Cathex