Я считаю, что все ингредиенты для ответа на ваш вопрос (ы) уже есть в существующих ответах. Позвольте мне объединить и уточнить.
Позвольте мне повторить код вашего вопроса, чтобы предоставить ссылки на номера строк:
1 class A(Exception): pass
2 class B(Exception): pass
3
4 try:
5 try:
6 raise A('first')
7 finally:
8 raise B('second')
9 except X as c:
10 print(c)
Итак, чтобы ответить на ваши вопросы:
- Куда делось мое первое исключение?
Ваше первое исключение A
вызывается в строке 6. Предложение finally
в строке 7 - это всегда , выполняемое, как только остается блок try
(строки 5-6), независимо от того, если он оставлен из-за успешного завершения или из-за возбужденного исключения.
Во время выполнения предложения finally
в строке 8 возникает еще одно исключение B
. Как указали Леннарт и Игнацио, можно отследить только одно исключение - последнее, о котором недавно говорили. Таким образом, как только значение B
повышается, общий блок try
(строки 4-8) завершается, и исключение B
перехватывается оператором except
в строке 9, если оно совпадает (если X
) B
).
- Почему ловится только самое внешнее исключение?
Надеюсь, теперь это ясно из моего объяснения 1. Вы можете поймать внутреннее / нижнее / первое исключение, хотя. Чтобы объединить ответ Леннарта, слегка модифицированный, вот как можно поймать оба:
class A(Exception): pass
class B(Exception): pass
try:
try:
raise A('first')
except A as e:
raise B('second', e)
except Exception as c:
print(c)
Вывод:
('second', A('first',))
- Как мне убрать крайнее исключение и перевыпустить более ранние исключения?
В примере Леннарта решением этого вопроса является строка except A as e
, где внутреннее / нижнее / первое исключение перехватывается и сохраняется в переменной e
.
Как общее ощущение того, когда нужно ловить исключения, когда их игнорировать, а когда повторно поднимать, возможно этот вопрос и ответ Алекса Мартелли помогают.