python: поток исключений: продолжать блокировать блок после захвата?

Мне любопытно, есть ли в python способ продолжить работу в блоке try/catch, после того как вы поймаете исключение, посмотрите на его свойства и, если это не актуально, продолжите вниз по стеку.

try:
    # Code
except AppleError as apple_ex:
    # look at 'apple_ex.error_code' error body, and if not relevant, 
    # continue on to next down the catch block...
    # In other words, proceed to except BananaError and so on down.
except BananaError as banana_ex:
    # ...
except Exception as ex:
    # ...

person jeff00seattle    schedule 20.11.2016    source источник


Ответы (3)


AppleError по-прежнему является AppleError, а не BananaError, даже если error_code не имеет значения, поэтому нет смысла переходить на BananaError.

Вместо этого вы можете определить конкретные ошибки для разных кодов ошибок:

GRANNY_SMITH_ERROR = 1
MACINTOSH_ERROR = 2
class AppleError(Exception): 
    def __init__(self, error_code, *args):
        super(AppleError, self).__init__(*args)
        self.error_code = error_code

class GrannySmithError(AppleError):
    def __init__(self, *args):
        super(GrannySmithError, self).__init__(GRANNY_SMITH_ERROR, *args)

class MacintoshError(AppleError):
    def __init__(self, *args):
        super(MacintoshError, self).__init__(MACINTOSH_ERROR, *args)

Затем вы можете попытаться сопоставить конкретную ошибку:

try: raise MacintoshError()
except MacintoshError as exc: print("mac")
except GrannySmithError as exc: print("granny smith")

Если вы не хотите различать разные типы ошибок Apple, вы все равно можете перехватывать все ошибки Apple:

try: raise MacintoshError()
except AppleError as exc: print("generic apple")

Вы можете комбинировать их, например, выполняя специальную обработку только для GrannySmith, а не для Macintosh:

try: raise MacintoshError()
except GrannySmithError as exc: print("granny smith")
except AppleError as exc: print("generic apple")

Важно перечислить ошибки от наиболее конкретных к наименее конкретным. Если вы проверите AppleError перед GrannySmithError, то он никогда не войдет в блок GrannySmith.

person Neapolitan    schedule 21.11.2016

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

try:
    raise AttributeError()
except AttributeError:
    raise TypeError()
except TypeError:
    print("it got caught") # will not catch the TypeError raised above

Итак, в вашем try мы поднимаем AttributeError, ловим его, а затем поднимаем TypeError внутри, ловя AttributeError.

except TypeError не поймает этого TypeError.

В зависимости от того, как вы объясняете свою проблему, вам нужно переосмыслить, как вы обрабатываете свои исключения, и посмотреть, можете ли вы определить обработку ошибок где-то еще и вызвать ошибку здесь.

Например:

def some_func():
    try:
        thing()
    except SomeException:
        # analyze the exception here and raise the error you *should* raise
        if apple_error_thing:
            raise AppleError
        elif banana_error_thing:
            raise BananaError
        else:
            raise UnknownException


def your_func():
    try:
        some_func()
    except AppleError as e:
        print('Apple')
    except BananaError as e:
        print('Banana')
    except UnknownException as e:
        print('Unknown')
person idjaw    schedule 20.11.2016

Нет, это невозможно. После того, как исключение обработано внутренним except, оно не может быть обработано внешним except:

Из документов по оператору try:

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

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

try:
    try:
        raise ZeroDivisionError
    except ZeroDivisionError as e:
        print("caught")
        raise ZeroDivisionError
except ZeroDivisionError as f:
    print("caught")

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

person Dimitris Fasarakis Hilliard    schedule 20.11.2016