Обработка исключений в Python с использованием класса - PullRequest
0 голосов
/ 19 октября 2018

У меня есть сомнения в исключении Python.Ниже код взят из документа Python, и я в какой-то момент запутался.Если кто-то может помочь, буду благодарен.Здесь этот код дает вывод в виде:

BCD

class B(Exception):
    pass
class C(B):
    pass
class D(C):
    pass
for cls in [B, C, D]:
    try:
        raise cls()
    except D:
        print("D")
    except C:
        print("C")
    except B:
        print("B")

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

BBB

class B(Exception):
    pass
class C(B):
    pass
class D(C):
    pass
for cls in [B, C, D]:
    try:
        raise cls()
    except B:
        print("B")
    except C:
        print("C")
    except D:
        print("D")

Когда я запускаю этот код без блока try, как показано ниже:

class B(Exception):
    pass
class C(B):
    pass
class D(C):
    pass
for cls in [B, C, D]:
    raise cls()

Здесь вывод:

Traceback (most recent call last):
  File "C:/Users/885710/Documents/PY/ErrorHandling.py", line 12, in <module>
    raise cls()
B

Аналогично приведенному ниже коду:

class B(Exception):
    pass
class C(B):
    pass
class D(C):
    pass
for cls in [C,B, D]:
    raise cls()

Вывод такой:

Traceback (most recent call last):
  File "C:/Users/885710/Documents/PY/ErrorHandling.py", line 12, in <module>
    raise cls()
C

Я запутался, потому что, если я запускаю этот код отдельно, то он дает вывод как B или C или D, тогда почему в моемво втором фрагменте кода он выдает вывод как

B
B
B

, хотя, кроме случаев, определен для всех 3 классов B, C, D

Ответы [ 3 ]

0 голосов
/ 19 октября 2018

Документация Python гласит:

Класс в предложении кроме совместим с исключением, если это тот же класс или базовый класс

Следовательно, данный код:

for cls in [B, C, D]:
    try:
        raise cls()
    except D:
        print("D")
    except C:
        print("C")
    except B:
        print("B")

Можно упростить до следующего:

for cls in [B, C, D]:
    foo = cls()
    if isinstance(foo, D):
        print("D")
    elif isinstance(foo, C):
        print("C")
    elif isinstance(foo, B):
        print("B")

Тогда ваша модификация будет преобразована в:

for cls in [B, C, D]:
    foo = cls()
    if isinstance(foo, B):
        print("B")
    elif isinstance(foo, C):
        print("C")
    elif isinstance(foo, D):
        print("D")

Такнезависимо от того, является ли foo экземпляром B, C или D, он выполнит первый случай, потому что isinstance дает True и для экземпляров подкласса.

0 голосов
/ 19 октября 2018

Давайте сначала разберемся с иерархией классов, включенной в этот пример кода

class B(Exception):
    pass
class C(B):
    pass
class D(C):
    pass

B -> Базовый класс

C -> наследуется от B

D -> наследуетсяот C и C -> наследует от B

, таким образом, D -> наследует от B и C

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

Если вы не перехватили повышенное исключение, то базовому классу будет дан приоритет для перехвата.т.е. когда классы исключений наследуются, приоритет в except отдается классу BASE (в вашем коде это класс B).

Теперь первый случай:

for cls in [B, C, D]:
    try:
        raise cls()
    except D:
        print("D")
    except C:
        print("C")
    except B:
        print("B")

Iteration 1: элемент: B

Первый элемент управления проверяет except D, так как это не базовый класс и не соответствующий классна поднятый, тогда управление переместится на except C и, наконец, выполнит except B, таким образом печатая B.

Iteration 2: элемент: C

Первые контрольные проверкиexcept D, поскольку это не базовый класс и не соответствующий классу с поднятым классом, тогда элемент управления переместится на except C и выполнит except C, таким образом печатая C

Iteration 3: element:D

Первый элемент управления проверяет except D как соответствующий класс, затем элемент управления выполняет except D, таким образом печатает D

Теперь рассмотрим второй случай:

for cls in [B, C, D]:
    try:
        raise cls()
    except B:
        print("B")
    except C:
        print("C")
    except D:
        print("D")

Здесь B - базовый класс для классов C и D, поэтому, когда вы пишете except B в верхней части, кроме стека, элемент управления не переходит к последующим except C и except D.Таким образом, он выводит вывод как B для каждой итерации цикла for.

0 голосов
/ 19 октября 2018

Поскольку B является суперклассом C и D, ваша вторая версия всегда будет использовать первый блок except для B.Поскольку среда выполнения Python будет искать соответствующий блок except сверху вниз.Блок except совпадает, если исключение является экземпляром класса в блоке except.Если вы кидаете экземпляр C, например, этот блок будет совпадать, потому что C() (также) является экземпляром B.

Как правило, операторы except должны уменьшаться с большинстваспецифическое условие для наиболее общего состояния, например:

try:
    throw ...
except D: # the most specific class
    print("D")
except C: # is more specific than B but less than D
    print("C")
except B: # the most general class in your hierarchy
    print("B")
except BaseException as e: the most general exception class
    print(e.__class__.__name__)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...