Cattura KeyboardInterrupt in Python senza try-except
-
25-09-2019 - |
Domanda
C'è qualche modo in Python all'evento cattura KeyboardInterrupt
senza mettere tutto il codice all'interno di un'istruzione try
-except
?
Voglio uscire in modo pulito senza lasciare traccia se l'utente preme Ctrl + C .
Soluzione
Sì, è possibile installare un gestore di interrupt con il modulo segnale , e aspettare per sempre utilizzando un threading.Event :
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()
Altri suggerimenti
Se invece si è di non mostrare il traceback, rendere il 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ì, lo so che questo non risponde direttamente alla domanda, ma in realtà non è chiaro il motivo che necessitano di un blocco try / except è discutibile - forse questo lo rende meno fastidioso per l'OP)
Un'alternativa a impostare il proprio gestore di segnale è quello di utilizzare un contesto-manager per catturare l'eccezione e ignorarlo:
>>> 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
pur conservando alcune menzione esplicita di ciò che sta accadendo.
Questo permette anche di ignorare l'interrupt solo in alcune parti del codice senza dover impostare e resettare nuovamente l'everytime gestori di segnale.
So che questa è una vecchia questione, ma sono venuto qui prima e poi scoperto il modulo atexit
. Non so circa la sua esperienza cross-piattaforma o una lista completa di avvertimenti ancora, ma finora è esattamente quello che cercavo nel cercare di gestire post-KeyboardInterrupt
pulizia su Linux. Volevo solo gettare in un altro modo di affrontare il problema.
voglio fare post-uscita clean-up nel contesto delle operazioni di tessuto, in modo da imballaggio tutto in try
/ except
non era un'opzione per me. Mi sento come atexit
può essere una buona forma in una situazione del genere, in cui il codice non è al livello superiore del flusso di controllo.
atexit
è molto capace e fuori leggibile dalla scatola, per esempio:
import atexit
def goodbye():
print "You are now leaving the Python sector."
atexit.register(goodbye)
Si può anche usarlo come decoratore (a partire da 2.6, questo esempio è dalla documentazione):
import atexit
@atexit.register
def goodbye():
print "You are now leaving the Python sector."
Se si voleva renderlo specifico per KeyboardInterrupt
solo, la risposta di un'altra persona a questa domanda è probabilmente meglio.
Ma si noti che il modulo atexit
è solo ~ 70 linee di codice e non sarebbe difficile creare una versione simile che tratta le eccezioni in modo diverso, ad esempio passando le eccezioni come argomenti alle funzioni di callback. (La limitazione di atexit
che giustifichino una versione modificata: attualmente non posso concepire un modo per l'uscita-callback funzioni di conoscere le eccezioni, il gestore atexit
cattura l'eccezione, per chiamare la propria callback (s), poi ri -raises tale eccezione. Ma si potrebbe fare questo in modo diverso.)
Per maggiori informazioni visita:
- documentazione ufficiale sul
atexit
- Il Python Modulo del post Settimana , una buona introduzione
È possibile evitare che la stampa di una traccia dello stack per KeyboardInterrupt
senza try: ... except KeyboardInterrupt: pass
(la soluzione più ovvia e riordinata "migliore", ma sai già che e ha chiesto per qualcos'altro) sostituendo sys.excepthook
. Qualcosa di simile
def custom_excepthook(type, value, traceback):
if type is KeyboardInterrupt:
return # do nothing
else:
sys.__excepthook__(type, value, traceback)