Мое исключение автоматически вызывает себя после первого обработчика исключений, но не может вызвать его снова после завершения второго обработчика исключений.
Это часть серии исследовательских вопросов, где новые вопросы, которые являются более конкретными, используются для разработки ответов на более старые вопросы, которые являются более общими:
Этот пример демонстрирует, как исключение может автоматически вызываться после обработки, но не может быть вызвано во второй раз:
import _thread
import ctypes
import dis
import inspect
import sys
PyThreadState_SetAsyncExc = ctypes.pythonapi.PyThreadState_SetAsyncExc
# noinspection SpellCheckingInspection
PyThreadState_SetAsyncExc.argtypes = ctypes.c_ulong, ctypes.py_object
PyThreadState_SetAsyncExc.restype = ctypes.c_int
def main():
# noinspection PyPep8,PyBroadException
try:
try:
raise SpecialError
except SpecialError as error:
print(f'{error!r} was caught!')
# error.reset()
except:
print('Exception was caught again!')
print('You should not see this!')
class SpecialError(BaseException):
DEBUG = False
THROW = {dis.opmap['END_FINALLY'], dis.opmap['POP_EXCEPT']}
def __init__(self, *args):
super().__init__(*args)
self.__stack = []
self.__patch_trace()
def __patch_trace(self):
self.reset()
frame = inspect.currentframe()
while frame:
self.__stack.append((frame, frame.f_trace))
frame.f_trace = self.__trace
frame = frame.f_back
self.__stack.append(sys.gettrace())
sys.settrace(self.__trace)
# noinspection PyUnusedLocal
def __trace(self, frame, event, arg):
frame.f_trace_lines = False
frame.f_trace_opcodes = True
# noinspection SpellCheckingInspection
if event == 'opcode':
op = frame.f_code.co_code[frame.f_lasti]
if self.DEBUG:
print(dis.opname[op])
if op in self.THROW:
args = self.args
class StateInfo(type(self)):
def __init__(self):
super().__init__(*args)
PyThreadState_SetAsyncExc(_thread.get_ident(), StateInfo)
return self.__trace
def reset(self):
if self.__stack:
sys.settrace(self.__stack.pop())
while self.__stack:
frame, trace = self.__stack.pop()
frame.f_trace = trace
if __name__ == '__main__':
main()
Я ожидаю, что исключение должно автоматически подниматься в конце каждого блока обработчика исключений, где оно обрабатывается, но код в настоящее время делает это один раз.
- Что нужно сделать, чтобы исключение продолжало вызывать себя?
- Есть ли способ для экземпляра исключения обнаружить, что он вызывается (возможно, несколько раз), а не просто создается и инициализируется?
Этот вопрос не является дубликатом Как повторно вызвать исключение во вложенных блоках try / кроме? , поскольку этот вопрос не охватывает исключения, которые автоматически возникают при выходе из блока обработчика исключений, который не иметь явное выражение raise
в конце.