Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Обработка исключений в Python
Обработка исключений (exception handling) — это критический инструмент для написания надежного и устойчивого к ошибкам кода. Python предоставляет мощный механизм try-except-finally.
1. Базовый синтаксис try-except
# Базовая структура
try:
# Код, который может вызвать исключение
result = 10 / 0
except ZeroDivisionError:
# Обработка конкретного исключения
print("Нельзя делить на ноль!")
# Результат: печатает сообщение об ошибке вместо краша
2. Перехват нескольких исключений
try:
value = int("abc") # ValueError
except ValueError:
print("Ошибка: неверное значение")
except TypeError:
print("Ошибка: неверный тип")
except Exception as e:
print(f"Неожиданная ошибка: {e}")
Порядок важен — специфичные исключения должны идти первыми.
3. Несколько исключений в одном блоке
try:
value = int("abc")
except (ValueError, TypeError) as e:
print(f"Ошибка: {e}")
4. Блок else
Код в else выполняется, если исключения не было:
try:
number = int("123")
except ValueError:
print("Не число")
else:
print(f"Число: {number}") # Печатается только если не было ошибки
5. Блок finally
Код в finally выполняется ВСЕГДА (даже если было исключение):
try:
file = open("data.txt")
data = file.read()
except FileNotFoundError:
print("Файл не найден")
finally:
file.close() # Выполнится в любом случае
Обычно используется для очистки ресурсов.
6. Менеджер контекста (context manager)
Автоматически закрывает ресурсы (лучше чем finally):
# Без with — нужен finally
file = open("data.txt")
try:
data = file.read()
except FileNotFoundError:
print("Файл не найден")
finally:
file.close()
# С with — автоматическое закрытие
with open("data.txt") as file:
data = file.read() # Файл закроется автоматически
7. Иерархия исключений
Все исключения в Python наследуются от BaseException:
# Иерархия
BaseException
├── SystemExit
├── KeyboardInterrupt
└── Exception
├── StopIteration
├── GeneratorExit
├── ArithmeticError
│ ├── ZeroDivisionError
│ └── OverflowError
├── LookupError
│ ├── IndexError
│ └── KeyError
├── NameError
├── TypeError
├── ValueError
├── RuntimeError
└── ... (еще много)
# ✅ Перехватывай Exception, не BaseException
try:
value = int("abc")
except Exception as e: # Ловит все Exception подклассы
print(f"Ошибка: {e}")
# ❌ Не перехватывай BaseException
# except BaseException: # Ловит и KeyboardInterrupt!
8. Создание пользовательских исключений
# Простое исключение
class InvalidUserError(Exception):
pass
# Исключение с дополнительной информацией
class ValidationError(Exception):
def __init__(self, field, message):
self.field = field
self.message = message
super().__init__(f"Ошибка {field}: {message}")
# Использование
try:
if not username:
raise ValidationError("username", "не может быть пустым")
except ValidationError as e:
print(f"Ошибка: {e.message}")
9. Цепочка исключений (exception chaining)
Сохрани оригинальное исключение при выбросе нового:
try:
result = 10 / 0
except ZeroDivisionError as e:
# Выбрось новое исключение, сохраняя информацию о старом
raise ValueError("Неверное число") from e
# Результат:
# ValueError: Неверное число
# The above exception was the direct cause of the following exception:
# ZeroDivisionError: division by zero
Без from e оригинальная ошибка может быть потеряна.
10. Получение информации об ошибке
import traceback
try:
result = 10 / 0
except Exception as e:
# Информация об исключении
print(f"Тип: {type(e).__name__}")
print(f"Сообщение: {str(e)}")
print(f"Args: {e.args}")
# Полная информация о стеке
print(traceback.format_exc())
11. Перехват и переброс
try:
data = fetch_data_from_api()
except requests.ConnectionError as e:
print(f"Ошибка подключения: {e}")
# Переброс исключения дальше
raise # Выбросит то же исключение
# Или переброс с логированием
import logging
try:
dangerous_operation()
except Exception as e:
logging.error(f"Ошибка: {e}", exc_info=True)
raise # Логируем и переидаем ошибку дальше
12. Условная обработка
try:
result = calculate(value)
except ValueError as e:
if "invalid" in str(e):
print("Неверное значение")
elif "out of range" in str(e):
print("Значение вне диапазона")
else:
raise # Если не знаем как обработать
13. Практический пример: API запрос с обработкой ошибок
import requests
from typing import Optional
def fetch_user(user_id: int) -> Optional[dict]:
try:
response = requests.get(f"https://api.example.com/users/{user_id}", timeout=5)
response.raise_for_status() # Выбросит HTTPError если статус ошибки
return response.json()
except requests.ConnectionError:
print("Ошибка подключения")
return None
except requests.Timeout:
print("Timeout — сервер не ответил")
return None
except requests.HTTPError as e:
if e.response.status_code == 404:
print("Пользователь не найден")
elif e.response.status_code == 401:
print("Не авторизован")
else:
print(f"HTTP ошибка: {e.response.status_code}")
return None
except ValueError as e:
print(f"Ошибка парсинга JSON: {e}")
return None
14. Обработка исключений в циклах
# ❌ Неправильно — пропустит весь цикл
try:
for item in items:
process(item)
except Exception:
print("Ошибка")
# ✅ Правильно — продолжит цикл
for item in items:
try:
process(item)
except Exception as e:
print(f"Ошибка для {item}: {e}")
continue
15. Контекстный менеджер для управления исключениями
from contextlib import suppress, contextmanager
# suppress — игнорирует исключение
from contextlib import suppress
with suppress(FileNotFoundError):
os.remove("nonexistent.txt") # Ошибка будет проигнорирована
# Кастомный менеджер контекста
@contextmanager
def safe_operation(name):
try:
print(f"Начало: {name}")
yield
except Exception as e:
print(f"Ошибка в {name}: {e}")
finally:
print(f"Конец: {name}")
with safe_operation("wichtige операция"):
result = 10 / 0 # Будет обработана
Лучшие практики
✅ Ловй специфичные исключения — не Exception или BaseException ✅ Используй except Exception — для неожиданных ошибок ✅ Используй finally — для очистки ресурсов ✅ Используй with — вместо try-finally для файлов ✅ Цепочка исключений — используй from для контекста ✅ Логирование — логируй исключения с трассировкой стека ✅ Переброс исключений — если не можешь их обработать ✅ Создавай свои исключения — для специфичных ошибок ✅ Не молчи об ошибках — всегда логируй или выбрасывай
Правильная обработка исключений делает код надежным и легко отлаживаемым.