Почему исключение не вызывается автоматически после второго обработчика исключений? - PullRequest
0 голосов
/ 15 мая 2019

Мое исключение автоматически вызывает себя после первого обработчика исключений, но не может вызвать его снова после завершения второго обработчика исключений.

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

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

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()

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

  1. Что нужно сделать, чтобы исключение продолжало вызывать себя?
  2. Есть ли способ для экземпляра исключения обнаружить, что он вызывается (возможно, несколько раз), а не просто создается и инициализируется?

Этот вопрос не является дубликатом Как повторно вызвать исключение во вложенных блоках try / кроме? , поскольку этот вопрос не охватывает исключения, которые автоматически возникают при выходе из блока обработчика исключений, который не иметь явное выражение raise в конце.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...