2010-11-17 12 views

Odpowiedz

122

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) 
+8

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

+6

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ą). –

+1

Jeśli używasz sugestii Chrisa Morgana użycia 'time' (tak, jak powinieneś), nie zapomnij o" czasie importu ":) – Seaux

4

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) 
+0

Chcę czystej wyjście bez śladu jeśli użytkownik naciśnie ctrl-c – Alex

+0

catched ==> caught –

+7

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

25

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)

+2

Z jakiegoś powodu nie zawsze działa to dla mnie. 'signal.signal (signal.SIGINT, lambda, f: sys.exit (0))' always does. –

+0

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. –

+0

Jest jeszcze jedno pytanie o Ctrl + C z pygtk: http://stackoverflow.com/questions/16410852/keyboard-interrupt-with-with-python-gtk – bgporter

23

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.

+1

miło, to rozwiązanie wydaje się nieco bardziej bezpośrednie w wyrażaniu cel raczej niż radzenie sobie z sygnałami. – Seaux

4

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:

Powiązane problemy