Відповіді:
Так, ви можете встановити обробник переривань, використовуючи сигнал модуля , і вічно чекати, використовуючи нитку .
import signal
import sys
import time
import threading
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()
while True: continue
. (У такому стилі все-таки while True: pass
було б акуратніше.) Це було б дуже марно; спробуйте щось на кшталт while True: time.sleep(60 * 60 * 24)
(спати протягом дня - це цілком довільна цифра).
time
(як слід), не забудьте import time
:)
Якщо все, що вам потрібно, це не показувати прослідкування, зробіть свій код таким:
## all your app logic here
def main():
## whatever your app does.
if __name__ == "__main__":
try:
main()
except KeyboardInterrupt:
# do nothing here
pass
(Так, я знаю, що це не відповідає безпосередньо на запитання, але не зовсім зрозуміло, чому потрібна спроба / крім блоку є заперечною - можливо, це робить менше прикрою для ОП)
signal.signal( signal.SIGINT, lambda s, f : sys.exit(0))
завжди робить.
Альтернативою встановлення власного обробника сигналів є використання контекстного менеджера, щоб зловити виняток та проігнорувати його:
>>> 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
модуль. Я ще не знаю про його крос-платформенний трек чи повний перелік застережень, але поки що це саме те, що я шукав, намагаючись обробити пост KeyboardInterrupt
очищення в 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
цього вимагає модифікованої версії. Наразі я не можу уявити спосіб для функцій виходу-виклику знати про винятки; atexit
обробник виловлює виняток, викликає зворотний зворотний дзвінок, а потім повторно підвищує це виняток. Але ви могли це зробити інакше.)
Для отримання додаткової інформації див:
atexit
Ви можете запобігти друкуванню сліду стека 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)
Я спробував всі запропоновані рішення, але мені довелося імпровізувати код, щоб насправді змусити його працювати. Далі - мій підручний код:
import signal
import sys
import time
def signal_handler(signal, frame):
print('You pressed Ctrl+C!')
print(signal) # Value is 2 for CTRL + C
print(frame) # Where your execution of program is at moment - the Line Number
sys.exit(0)
#Assign Handler Function
signal.signal(signal.SIGINT, signal_handler)
# Simple Time Loop of 5 Seconds
secondsCount = 5
print('Press Ctrl+C in next '+str(secondsCount))
timeLoopRun = True
while timeLoopRun:
time.sleep(1)
if secondsCount < 1:
timeLoopRun = False
print('Closing in '+ str(secondsCount)+ ' seconds')
secondsCount = secondsCount - 1