Подтвердить что ты не робот

Захват KeyboardInterrupt в Python во время выключения программы

Я пишу утилиту командной строки в Python, которая, так как это производственный код, должна быть способна отключиться, не выгружая кучу вещей (коды ошибок, трассировки стека и т.д.) на экран. Это означает, что мне нужно ловить клавиатурные прерывания.

Я попытался использовать оба блока catch try, например:

if __name__ == '__main__':
    try:
        main()
    except KeyboardInterrupt:
        print 'Interrupted'
        sys.exit(0)

и поймать сам сигнал (как в этом сообщении):

import signal
import sys

def sigint_handler(signal, frame):
    print 'Interrupted'
    sys.exit(0)
signal.signal(signal.SIGINT, sigint_handler)

Оба метода, похоже, работают достаточно хорошо во время нормальной работы. Однако, если прерывание происходит во время кода очистки в конце приложения, Python, кажется, всегда печатает что-то на экране. Захват прерывания дает

^CInterrupted
Exception KeyboardInterrupt in <bound method MyClass.__del__ of <path.to.MyClass object at 0x802852b90>> ignored

тогда как обработка сигнала дает либо

^CInterrupted
Exception SystemExit: 0 in <Finalize object, dead> ignored

или

^CInterrupted
Exception SystemExit: 0 in <bound method MyClass.__del__ of <path.to.MyClass object at 0x802854a90>> ignored

Эти ошибки не только уродливы, но и не очень полезны (особенно для конечного пользователя без исходного кода)!

Код очистки для этого приложения довольно большой, поэтому есть приличный шанс, что эта проблема будет затронута реальными пользователями. Есть ли способ уловить или заблокировать этот вывод, или это просто то, с чем мне придется иметь дело?

4b9b3361

Ответ 1

Оформить заказ в этой теме, есть полезная информация о выходе и трассировке.

Если вас больше интересует просто убийство программы, попробуйте что-то вроде этого (это также поможет избавиться от кода очистки):

if __name__ == '__main__':
    try:
        main()
    except KeyboardInterrupt:
        print('Interrupted')
        try:
            sys.exit(0)
        except SystemExit:
            os._exit(0)

Ответ 2

Вы можете игнорировать SIGINT после завершения работы, вызывая signal.signal(signal.SIGINT, signal.SIG_IGN), прежде чем запускать код очистки.