Risposte:
Sì, puoi installare un gestore di interrupt utilizzando il segnale del modulo e attendere per sempre utilizzando un threading .
import signal
import sys
import time
import threading
def signal_handler(signal, frame):
print('You pressed Ctrl+C!')
sys.exit(0)
signal.signal(signal.SIGINT, signal_handler)
print('Press Ctrl+C')
forever = threading.Event()
forever.wait()
while True: continue
, però. (In quello stile, while True: pass
sarebbe più ordinato, comunque.) Sarebbe molto dispendioso; prova qualcosa di simile while True: time.sleep(60 * 60 * 24)
(dormire per un giorno alla volta è una cifra del tutto arbitraria).
time
(come dovresti), non dimenticare di import time
:)
Se tutto ciò che vuoi è non mostrare il traceback, crea il tuo codice in questo modo:
## all your app logic here
def main():
## whatever your app does.
if __name__ == "__main__":
try:
main()
except KeyboardInterrupt:
# do nothing here
pass
(Sì, so che questo non risponde direttamente alla domanda, ma non è molto chiaro perché sia discutibile la necessità di un blocco try / tranne - forse questo lo rende meno fastidioso per l'OP)
signal.signal( signal.SIGINT, lambda s, f : sys.exit(0))
lo fa sempre.
Un'alternativa all'impostazione del proprio gestore di segnali è utilizzare un gestore di contesto per catturare l'eccezione e ignorarla:
>>> class CleanExit(object):
... def __enter__(self):
... return self
... def __exit__(self, exc_type, exc_value, exc_tb):
... if exc_type is KeyboardInterrupt:
... return True
... return exc_type is None
...
>>> with CleanExit():
... input() #just to test it
...
>>>
Questo rimuove il blocco try
- except
preservando una menzione esplicita di ciò che sta accadendo.
Ciò consente anche di ignorare l'interrupt solo in alcune parti del codice senza dover impostare e reimpostare nuovamente i gestori di segnale ogni volta.
So che questa è una vecchia domanda, ma prima sono venuto qui e poi ho scoperto il atexit
modulo. Non so ancora del suo track record multipiattaforma o di un elenco completo di avvertenze, ma finora è esattamente quello che stavo cercando nel tentativo di gestire la post- KeyboardInterrupt
pulizia su Linux. Volevo solo lanciare un altro modo di affrontare il problema.
Voglio eseguire la pulizia post-uscita nel contesto delle operazioni di Fabric, quindi anche il wrapping di tutto try
/ except
non era un'opzione per me. Penso che atexit
possa essere una buona soluzione in una situazione del genere, in cui il tuo codice non è al livello più alto del flusso di controllo.
atexit
è molto capace e leggibile fuori dagli schemi, ad esempio:
import atexit
def goodbye():
print "You are now leaving the Python sector."
atexit.register(goodbye)
Puoi anche usarlo come decoratore (a partire dalla 2.6; questo esempio è tratto dalla documentazione):
import atexit
@atexit.register
def goodbye():
print "You are now leaving the Python sector."
Se vuoi renderlo specifico KeyboardInterrupt
solo per, la risposta di un'altra persona a questa domanda è probabilmente migliore.
Ma si noti che il atexit
modulo è solo ~ 70 righe di codice e non sarebbe difficile creare una versione simile che tratti le eccezioni in modo diverso, ad esempio passando le eccezioni come argomenti alle funzioni di callback. (La limitazione di atexit
ciò giustificherebbe una versione modificata: attualmente non riesco a concepire un modo per le funzioni di callback di uscita di conoscere le eccezioni; il atexit
gestore cattura l'eccezione, chiama i tuoi callback, quindi solleva nuovamente quell'eccezione. Ma potresti farlo in modo diverso.)
Per maggiori informazioni vedere:
atexit
Puoi impedire la stampa di una traccia dello stack KeyboardInterrupt
senza try: ... except KeyboardInterrupt: pass
(la soluzione più ovvia e probabilmente "migliore", ma la conosci già e hai chiesto qualcos'altro) sostituendo sys.excepthook
. Qualcosa di simile a
def custom_excepthook(type, value, traceback):
if type is KeyboardInterrupt:
return # do nothing
else:
sys.__excepthook__(type, value, traceback)
Ho provato le soluzioni suggerite da tutti, ma ho dovuto improvvisare del codice da solo per farlo funzionare. Di seguito è il mio codice improvvisato:
import signal
import sys
import time
def signal_handler(signal, frame):
print('You pressed Ctrl+C!')
print(signal) # Value is 2 for CTRL + C
print(frame) # Where your execution of program is at moment - the Line Number
sys.exit(0)
#Assign Handler Function
signal.signal(signal.SIGINT, signal_handler)
# Simple Time Loop of 5 Seconds
secondsCount = 5
print('Press Ctrl+C in next '+str(secondsCount))
timeLoopRun = True
while timeLoopRun:
time.sleep(1)
if secondsCount < 1:
timeLoopRun = False
print('Closing in '+ str(secondsCount)+ ' seconds')
secondsCount = secondsCount - 1