выход(1) в обработчике сигнала просто ловится как SystemExit, так как в нем ничего нет

#python #signals

Вопрос:

У меня есть приложение, которое выглядит так:

 while True:
    try:
        self.try_to_read_usb_device()
        break
    except:
        time.sleep(1)
 

У меня также есть SIGALRM обработчик, который должен выйти из программы в случае, если она где-то застряла:

 def alarm_signal_handler(signal, frame):
    # Something went wrong
    exit(1)
 

Однако exit(1) просто попадается на попытку/исключение и отбрасывается, так как это то, что делает этот конкретный except .

Это для меня совершенно неожиданно.

В полном приложении будет много попыток/исключений, и я не вижу, чтобы я добавлял

 except SystemExit:
    exit(1)
 

или что-то для всех них.

Есть идеи, как мне следует обращаться с этим прецедентом?

Ответ №1:

Грязный путь

Вы можете использовать os._exit вместо sys.exit .

Обратите внимание, что у этого есть очевидные недостатки именно потому, что он не пройдет через исключение:

Завершите процесс со статусом n, не вызывая обработчики очистки, не очищая буферы stdio и т. Д.

Правильный путь

Я бы рекомендовал вместо этого изменить обработку исключений , чтобы перехватывать только вещи, от которых они наследуются Exception , потому что SystemExit не наследуются Exception именно по этой причине, поэтому они не будут пойманы случайно:

 except Exception:
 

Смотрите также SystemExit документацию:

Это исключение вызывается sys.exit() функцией. Он наследуется от BaseException вместо Exception , чтобы его случайно не поймал код, который ловит Exception . Это позволяет исключению правильно распространяться и вызывать выход интерпретатора.

Это также относится KeyboardInterrupt , кстати, к — Ctrl C будет пойман, except: но не except Exception: пойман .

Это довольно хорошо проиллюстрировано на диаграмме иерархии исключений в документах Python, которую вы можете найти здесь.