Иерархия исключений и несколько except
Иерархия исключений Python: BaseException и Exception, несколько блоков except, порядок обработчиков и перехват группы ошибок.
Все исключения Python образуют дерево наследования. Зная иерархию, вы точно выбираете, какие ошибки обрабатывать, а каким давать всплывать выше.
Дерево исключений (главные ветви)
BaseException
├── SystemExit # sys.exit()
├── KeyboardInterrupt # Ctrl+C
└── Exception # все «обычные» ошибки
├── ValueError
├── TypeError
├── ArithmeticError
│ └── ZeroDivisionError
├── LookupError
│ ├── IndexError
│ └── KeyError
├── OSError
│ └── FileNotFoundError
└── ...и другие
Перехват родительского класса ловит и все его потомки. Например,
except LookupErrorпоймает иIndexError, иKeyError.
Несколько блоков except
def divide(a, b):
try:
result = a / b
return result
except ZeroDivisionError:
print("Ошибка: делитель равен нулю")
except TypeError:
print("Ошибка: оба аргумента должны быть числами")
print(divide(10, 2)) # 5.0
print(divide(10, 0)) # Ошибка: делитель равен нулю
print(divide(10, "x")) # Ошибка: оба аргумента должны быть числами
Вывод:
5.0 Ошибка: делитель равен нулю Ошибка: оба аргумента должны быть числами
Python проверяет блоки except сверху вниз и выполняет только первый подходящий.
Порядок важен: частное раньше общего
# Неправильно: Exception поймает всё первым
try:
x = int("abc")
except Exception:
print("Общая ошибка")
except ValueError:
print("ValueError") # никогда не выполнится!
# Правильно: сначала конкретный, потом общий
try:
x = int("abc")
except ValueError:
print("Не удалось преобразовать строку в число")
except Exception as e:
print(f"Другая ошибка: {e}")
Вывод:
Не удалось преобразовать строку в число
Перехват нескольких типов сразу
Если несколько исключений обрабатываются одинаково, их объединяют в кортеж:
def get_element(data, key):
try:
return data[key]
except (KeyError, IndexError) as e:
print(f"Элемент не найден: {e}")
return None
print(get_element({"a": 1}, "b")) # Элемент не найден: 'b'
print(get_element([1, 2, 3], 10)) # Элемент не найден: list index out of range
Вывод:
Элемент не найден: 'b' Элемент не найден: list index out of range
Коротко
- Все исключения наследуют от
BaseException; «обычные» ошибки — отException. - Несколько блоков
exceptпроверяются сверху вниз — выполняется только первый совпавший. - Ставьте конкретные исключения перед общими (например,
ValueErrorпередException). - Несколько типов в одном блоке — через кортеж:
except (ValueError, TypeError).
Проверьте себя
1. В каком порядке Python проверяет несколько блоков except?
AВ случайном порядке
BСначала самый общий, потом конкретный
CСверху вниз, выполняет первый подходящий
DСнизу вверх
2. Как в одном except поймать и KeyError, и IndexError?
Aexcept KeyError or IndexError
Bexcept KeyError, IndexError
Cexcept (KeyError, IndexError)
Dexcept LookupError только
3. Какой базовый класс объединяет ValueError, TypeError и большинство «обычных» ошибок?
ABaseException
BException
CError
DRuntimeError