Есть ли способ в Python захватить событие KeyboardInterrupt
, не помещая весь код внутри инструкции try
- except
?
Я хочу чисто выйти без следа, если пользователь нажимает ctrl - c.
Захват клавиатуры прерывается в Python без try-except
Ответ 1
Да, вы можете установить обработчик прерываний с помощью сигнального модуля.
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)
Ответ 2
Если вы хотите не показывать трассировку, сделайте свой код следующим:
## 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)
Ответ 3
Альтернативой настройке вашего собственного обработчика сигналов является использование контекстного менеджера, чтобы поймать исключение и проигнорировать его:
>>> 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
, сохраняя некоторое явное упоминание о том, что происходит.
Это также позволяет игнорировать прерывание только в некоторых частях вашего кода без необходимости устанавливать и reset снова обработчики сигналов каждый раз.
Ответ 4
Вы можете предотвратить печать трассировки стека для 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)
Ответ 5
Я знаю, что это старый вопрос, но я пришел сюда первым, а затем открыл модуль atexit
. Я не знаю о его кросс-платформенной записи или полном списке предостережений, но пока это именно то, что я искал, пытаясь обработать post-KeyboardInterrupt
cleanup в Linux. Просто хотел бросить другой подход к проблеме.
Я хочу выполнить очистку после выхода в контексте операций с Fabric, поэтому обернуть все в 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
ловит исключение, вызывает ваш обратный вызов (s), затем повторно вызывает это исключение, но вы можете сделать это по-другому.)
Подробнее см.:
- Официальная документация по
atexit
- Python Module of the week post, хорошее введение