Обработка исключений Python Вернуться к строке, продолжить

Я решаю много проблем с кодированием Project Euler, и Python — мой любимый язык. Многие программы обычно выполняются целую вечность, поэтому я работаю над реализацией чего-то, что поможет предоставить диагностическую информацию о состоянии программы: когда происходит KeyboardInterrupt, я хочу иметь возможность печатать, как долго программа работает, и некоторые информация, которая поможет мне понять, сколько времени это может занять.

Проблема с этим заключается в том, что перехват KeyboardInterrupt при нажатии Ctrl-C для меня все еще выходит из программы ... и я думаю, что это во многом связано либо со структурой этого кода, либо, надеюсь, с чем-то в Python. нашел еще.

Я хочу, чтобы мой код возобновлялся с той же строки сразу после перехвата KeyboardInterrupt.

Вот пример того, как может выглядеть этот код:

     try:
         ...
         ...
         ... #I interrupt code here and hopefully keep going!
         ...
         ...
     except KeyboardInterrupt:
         ...
     finally:
         ...

Я надеюсь, что кто-то понимает цель этого и может помочь мне найти способ сделать это или обойти этот уродливый способ вызова перерыва в работающем коде.


person Community    schedule 28.06.2016    source источник
comment
Я думаю, что вы ищете обработчик сигналов. См. этот ответ. Конечно, это означает, что вы теряете возможность остановить свою программу с помощью Ctrl-C.   -  person Shakkhar    schedule 28.06.2016
comment
Отличная альтернатива! Спасибо, что указали мне на это @Shakkhar   -  person    schedule 28.06.2016
comment
Кстати, если вы programs typically take forever to complete, вы можете прочитать эту лекцию PyCon о том, какие у вас есть возможности облегчить ситуацию: drive.google.com/open?id=0Bw5McUt95YdeMlNiX2VSR1lFRHM   -  person boardrider    schedule 28.06.2016


Ответы (2)


Как правило, вы никогда не сможете вернуть выполнение в конкретный сегмент кода после того, как в блоке try было инициировано исключение, учитывая, что исключение может возникнуть где-то глубоко с рядом других состояний, на которые влияют другие побочные эффекты в других потоках. Хотя это, вероятно, не относится к вашей программе, учитывая, что в Python нет общего решения, разрешающего это, то, что вы хотите сделать, в основном невозможно с помощью обработки исключений.

Однако обработчик по умолчанию для сигнала SIGINT должен генерировать исключение KeyboardInterrupt — если вы можете перехватить это, чтобы сделать что-то еще, вы можете практически добиться этого. Вот простая программа:

import signal
import pdb

def signal_handler(signal, frame):
    pdb.set_trace()

signal.signal(signal.SIGINT, signal_handler)

count = 0
while True:
    count += 1

Обработчик SIGINT теперь представляет собой просто функцию, которая вызывает отладчик в текущем кадре, и при этом всякий раз, когда нажимается Ctrl-C, отладчик запускается именно в той точке внутри кадра, где находится код. Конечно, вы можете просто пойти и проверить значения следующим образом:

$ python /tmp/script.py 
^C--Return--
> /tmp/script.py(5)signal_handler()->None
-> pdb.set_trace()
(Pdb) u
> /tmp/script.py(10)<module>()
-> while True:
(Pdb) pp count
13321869
(Pdb) c
^C--Return--
> /tmp/script.py(5)signal_handler()->None
-> pdb.set_trace()
(Pdb) quit
Traceback (most recent call last):
...
    if self.quitting: raise BdbQuit
bdb.BdbQuit

Таким образом, отладчик был запущен после того, как ctrl-c был выполнен, затем я сделал шаг up к кадру, где выполнялся цикл (в вашем случае, ваш код), затем cпродолжил выполнение, снова убил его и вызвал плохой выход (набрав quit) который завершает программу. Если вы включите это, вы можете в любой момент сломаться и проверить значения вашей программы в любом месте.

person metatoaster    schedule 28.06.2016
comment
вы опередили меня в ответе, но я очень долго искал свою цитату, поэтому все равно опубликовал свой ответ :) - person en_Knight; 28.06.2016
comment
О, так что использование Ctrl-C в качестве триггера для отладки дает тот же предполагаемый эффект. Это, безусловно, то, что я хотел бы рассмотреть. Выйдите, проверьте статус и продолжайте. @metatoaster не могли бы вы сказать, что его также можно настроить для любого пользовательского вывода? - person ; 28.06.2016
comment
Что вы подразумеваете под пользовательским вводом? Если вы хотите изменить какие-либо значения, присвоенные любой данной переменной в любом данном кадре, вы можете просто сделать это через отладчик. - person metatoaster; 28.06.2016

— Ага, — сказал Гарри. "В . . . в минуту. Я просто проясню это». Он указал на разбитую чашу на полу. Рон кивнул и ушел. — Репаро, — пробормотал Гарри, указывая палочкой на осколки. Они летели вместе, как новенькие, но эссенцию муртлепа не вернули в миску. - Гарри Поттер и орден Фениксов

Как только возникает прерывание клавиатуры, эта информация потерян - попытка/поймать позволяет программе восстановиться, но то, что происходило до этого, теряется навсегда [1].

К счастью, прерывание клавиатуры на самом деле является сигналом на уровне c - вы можете перехватывать и обрабатывать его отдельно, если хотите . traceback и модули самоанализа должны быть полезны

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

У нас по-прежнему существует проблема, заключающаяся в том, что в некоторых реализациях сигналы, генерируемые клавиатурой (например, SIGINT), доставляются во все потоки (например, SGI), а в других (например, Solaris) такие сигналы доставляются в один случайный поток (промежуточной возможностью может быть доставить его в основной поток -- POSIX?). На данный момент у нас есть работающая реализация, которая работает во всех трех случаях — обработчик игнорирует сигналы, если getpid() не такой, как в основном потоке. XXX Это взлом.


Сноски

[1] Хорошо, нет. Вы можете использовать достаточно самоанализа, чтобы делать что-либо в python, но это ужасная идея и не соответствует моей цитате. Эти люди сделали это за вас, если вы действительно хотите сделать что-то ужасное: https://github.com/ajalt/fuckitpy

person en_Knight    schedule 28.06.2016