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)