Capture keyboardinterrupt в Python без try-except
Есть ли какой-то способ в Python захватить событие KeyboardInterrupt, не помещая весь код внутрь try-except заявление?
Я хочу чисто выйти без следа, если пользователь нажимает Ctrl+С.
5 ответов:
Да, вы можете установить обработчик прерываний, используя модульsignal , и ждать вечно, используя threading.Событие :
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') forever = threading.Event() forever.wait()
Если все, что вы хотите, это не показывать обратную трассировку, сделайте свой код следующим образом:
## all your app logic here def main(): ## whatever your app does. if __name__ == "__main__": try: main() except KeyboardInterrupt: # do nothing here pass(Да, я знаю, что это не дает прямого ответа на вопрос, но не совсем ясно, почему необходимость в блоке try / except нежелательна - возможно, это делает его менее раздражающим для OP)
Альтернативой настройке собственного обработчика сигналов является использование контекст-менеджера для перехвата исключения и игнорирования его:
>>> 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 ... >>>Это удаляет
try-exceptблок, сохраняя при этом некоторые явные упоминания о том, что происходит.Это также позволяет игнорировать прерывание только в некоторых частях кода, не устанавливая и не сбрасывая каждый раз обработчики сигналов.
Я знаю, что это старый вопрос, но я пришел сюда первым, а затем обнаружил модуль
atexit. Я еще не знаю о его кросс-платформенном послужном списке или полном списке предостережений, но пока это именно то, что я искал, пытаясь справиться с post-KeyboardInterruptочисткой в Linux. Просто хотел бросить в другой способ подхода к проблеме.Я хочу сделать очистку после выхода в контексте операций с тканями, поэтому все обертывание
try/exceptдля меня это тоже не вариант. Я почувствуйте, какatexitможет хорошо подойти в такой ситуации,когда ваш код не находится на верхнем уровне потока управления.
atexitочень способный и читаемый из коробки, например:import atexit def goodbye(): print "You are now leaving the Python sector." atexit.register(goodbye)Вы также можете использовать его в качестве декоратора (начиная с 2.6; этот пример взят из документации):
import atexit @atexit.register def goodbye(): print "You are now leaving the Python sector."Если вы хотите сделать его специфичным только для
KeyboardInterrupt, Ответ другого человека на этот вопрос, вероятно, лучше.Но обратите внимание, что модуль
atexit- это всего лишь ~70 строк кода, и он было бы нетрудно создать аналогичную версию, которая по-разному трактует исключения, например передавая исключения в качестве аргументов функциям обратного вызова. (Ограничениеatexit, которое гарантировало бы модифицированную версию: в настоящее время я не могу представить себе способ для функций exit-callback узнать об исключениях; обработчикatexitловит исключение, вызывает ваш callback(ы), а затем повторно вызывает это исключение. Но вы могли бы сделать это по-другому.)Для получения дополнительной информации смотрите:
- официальная документация по
atexit- модуль Python недели post , хорошее вступление
Вы можете запретить печать трассировки стека для
KeyboardInterrupt, Безtry: ... except KeyboardInterrupt: pass(наиболее очевидное и приемлемое "лучшее" решение, но вы уже знаете его и попросили что-то другое), заменивsys.excepthook. Что-то вродеdef custom_excepthook(type, value, traceback): if type is KeyboardInterrupt: return # do nothing else: sys.__excepthook__(type, value, traceback)