Создайте общий класс исключений при повторной реализации в Python - PullRequest
1 голос
/ 17 февраля 2020

Как объясняется в заголовке, я хочу создать общий класс исключений для наследования от встроенных классов исключений, которые позднее будут обнаружены в других классах.

Вот мой код:

from functools import wraps


class ControlledException(TypeError, AttributeError):
    """A generic exception on the program's domain."""


class WithRetry:
    def __init__(self, retries_limit=3, allowed_exceptions=None):
        self.retries_limit = retries_limit
        self.allowed_exceptions = allowed_exceptions or (ControlledException,)

    def __call__(self, operation):
        @wraps(operation)
        def wrapped(*args, **kwargs):
            last_raised = None

            for _ in range(self.retries_limit):
                try:
                    return operation(*args, **kwargs)
                except self.allowed_exceptions as e:
                    print(f'retrying {operation.__qualname__} due to {e}')
                    last_raised = e
            raise last_raised

        return wrapped


@WithRetry()
def test(x):
    x = x + 1
    print(x)


test('a')

ControlledException класс наследует два исключения, TypeError и AttributeError, которые я хочу поймать. В этом случае программа поймает TypeError.

И я понятия не имею, почему параметр self.allowed_exceptions не влияет на (ControlledException,) ... Однако, если я изменяю (ControlledException,) в Exception или TypeError ошибка перехватывается.

1 Ответ

0 голосов
/ 17 февраля 2020

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

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

from functools import wraps


class ControlledException(TypeError, AttributeError):
    """A generic exception on the program's domain."""


class WithRetry:
    def __init__(self, retries_limit=3, allowed_exceptions=None):
        self.retries_limit = retries_limit
        self.allowed_exceptions = allowed_exceptions or (ControlledException,)

    def __call__(self, operation):
        @wraps(operation)
        def wrapped(*args, **kwargs):

            for _ in range(self.retries_limit):
                try:
                    return operation(*args, **kwargs)

                # if you want to catch the error, you have to catch the original
                # exceptions as opposed to custom exceptions
                except (TypeError, AttributeError) as exc:
                    print(f"retrying {operation.__qualname__} due to {exc}")

                    # this suppresses the original error message and raises your
                    # custom exception
                    raise ControlledException("Here is your error message!!") from None

        return wrapped


@WithRetry()
def test(x):
    x = x + 1
    print(x)


test("a")

Это распечатывает:

retrying test due to can only concatenate str (not "int") to str
---------------------------------------------------------------------------
ControlledException                       Traceback (most recent call last)
<ipython-input-364-2a7d6eb73e92> in <module>
     38 
     39 
---> 40 test('a')

<ipython-input-364-2a7d6eb73e92> in wrapped(*args, **kwargs)
     27                     # this suppresses the original error message and raises your
     28                     # custom exception
---> 29                     raise ControlledException('Here is your error message!!') from None
     30 
     31         return wrapped

ControlledException: Here is your error message!!
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...