Czy istnieje sposób w Pythonie do przechwytywania zdarzenia KeyboardInterrupt
bez umieszczania całego kodu w oświadczeniu o numerze try
- except
? Chcę wyczyścić bez śladu, jeśli użytkownik naciśnie ctrl - c.Przechwytywanie przerw w klawiaturze w Pythonie bez prób - z wyjątkiem
Odpowiedz
Tak, można zainstalować program obsługi przerwań używając signal module.
import signal
import sys
import time
def signal_handler(signal, frame):
print 'You pressed Ctrl+C!'
sys.exit(0)
signal.signal(signal.SIGINT, signal_handler)
print 'Press Ctrl+C'
while True:
time.sleep(1)
Można uniemożliwić drukowanie śledzenia stosu dla KeyboardInterrupt
, bez try: ... except KeyboardInterrupt: pass
(najbardziej oczywiste i prawdopodobnie "najlepsze" rozwiązanie, ale już je znasz i poprosiłeś o coś innego), zastępując sys.excepthook
. Coś jak
def custom_excepthook(type, value, traceback):
if type is KeyboardInterrupt:
return # do nothing
else:
sys.__excepthook__(type, value, traceback)
Chcę czystej wyjście bez śladu jeśli użytkownik naciśnie ctrl-c – Alex
catched ==> caught –
To nie jest prawdą. Wyjątek KeyboardInterrupt jest tworzony podczas obsługi przerwań. Domyślny handler dla SIGINT podnosi KeyboardInterrupt, więc jeśli nie chcesz tego zachowania, wszystko, co musisz zrobić, to dostarczyć inną procedurę obsługi sygnału dla SIGINT. Twoje są poprawne w tym, że wyjątki mogą być obsługiwane tylko przy próbie/z tym wyjątkiem, ale w tym przypadku możesz zachować wyjątek od pierwszego podniesienia. – Matt
Jeśli wszystko czego chcę, to nie pokazują traceback, uczynić Twój kod tak:
## all your app logic here
def main():
## whatever your app does.
if __name__ == "__main__":
try:
main()
except KeyboardInterrupt:
# do nothing here
pass
(Tak, wiem, że to nie bezpośrednio odpowiedzieć na pytanie, ale to naprawdę nie jest wyjaśnić, dlaczego potrzeba try/except blok jest niepożądana - może to czyni go mniej irytującym dla OP)
Z jakiegoś powodu nie zawsze działa to dla mnie. 'signal.signal (signal.SIGINT, lambda, f: sys.exit (0))' always does. –
To nie zawsze działa z takimi rzeczami jak pygtk, który używa wątków. Czasami^C po prostu zabije bieżący wątek zamiast całego procesu, więc wyjątek będzie propagował tylko przez ten wątek. –
Jest jeszcze jedno pytanie o Ctrl + C z pygtk: http://stackoverflow.com/questions/16410852/keyboard-interrupt-with-with-python-gtk – bgporter
Alternatywą dla ustawiania własnego programu obsługi sygnału jest użycie menedżera kontekstu w celu wychwycenia wyjątku i zignorowania go:
>>> 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
...
>>>
Powoduje to usunięcie bloku try
- except
przy zachowaniu wyraźnej wzmianki o tym, co się dzieje.
Umożliwia to również ignorowanie przerwania tylko w niektórych częściach kodu bez konieczności ponownego ustawiania i resetowania procedur obsługi sygnału za każdym razem.
miło, to rozwiązanie wydaje się nieco bardziej bezpośrednie w wyrażaniu cel raczej niż radzenie sobie z sygnałami. – Seaux
Wiem, że to stare pytanie, ale najpierw przyjechałem tutaj, a potem odkryłem moduł atexit
. Nie wiem jeszcze o jego wieloplatformowej ścieżce ani pełnej liście zastrzeżeń, ale do tej pory dokładnie to właśnie szukałem, próbując uporać się z oczyszczaniem po Linuksie po oczyszczeniu. Chciałem po prostu w inny sposób podejść do problemu.
Chcę przeprowadzić czyszczenie po wyjściu w kontekście operacji Fabric, więc zawijanie wszystkiego w try
/except
również nie było dla mnie opcją. Czuję, że atexit
może być dobrym rozwiązaniem w takiej sytuacji, w której twój kod nie znajduje się na najwyższym poziomie przepływu sterowania.
atexit
jest bardzo zdolny i czytelne po wyjęciu z pudełka, na przykład:
import atexit
def goodbye():
print "You are now leaving the Python sector."
atexit.register(goodbye)
Można również wykorzystać go jako dekorator (od 2,6; ten przykład jest z docs):
import atexit
@atexit.register
def goodbye():
print "You are now leaving the Python sector."
Jeśli chcesz, aby było to tylko oznaczenie KeyboardInterrupt
, odpowiedź innej osoby na to pytanie jest prawdopodobnie lepsza.
Należy jednak zauważyć, że moduł atexit
to tylko ~ 70 linii kodu i nie byłoby trudno stworzyć podobną wersję, która traktuje wyjątki inaczej, na przykład przekazywanie wyjątków jako argumentów do funkcji wywołania zwrotnego.(Ograniczenie atexit
, które uzasadniałoby zmodyfikowaną wersję: obecnie nie potrafię wyobrazić sobie sposobu, w jaki funkcje wyjścia-wywołania będą wiedzieć o wyjątkach, uchwyt atexit
wychwytuje wyjątek, wywołuje wywołania zwrotne, a następnie ponownie .. -raises wyjątek Ale można to zrobić inaczej)
Aby uzyskać więcej informacji zobacz:
- Official documentation on
atexit
- The Python Module of the Week post, dobry wstęp
Zauważ, że istnieją pewne problemy specyficzne dla platformy z modułem sygnałowym - nie powinno to wpływać na ten plakat, ale "W systemie Windows, sygnał() można wywoływać tylko przy pomocy SIGABRT, SIGFPE, SIGILL, SIGINT, SIGSEGV lub SIGTERM, a ValueError zostanie podniesiony w każdym innym przypadku. " – bgporter
Działa również z wątkami. Mam nadzieję, że nigdy nie wykonasz 'while While True: continue'. (W tym stylu "while while True: pass" i tak byłby lepszy). Byłoby to bardzo marnotrawstwem; spróbuj czegoś takiego jak 'while while True: time.sleep (60 * 60 * 24)' (spanie przez jeden dzień na raz jest całkowicie dowolną postacią). –
Jeśli używasz sugestii Chrisa Morgana użycia 'time' (tak, jak powinieneś), nie zapomnij o" czasie importu ":) – Seaux