← Назад к вопросам
В чём разница между exception и BaseException?
2.0 Middle🔥 111 комментариев
#Python Core
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
В чём разница между Exception и BaseException
В Python есть два корневых класса для исключений: Exception и BaseException. Различие между ними критично для правильной обработки ошибок.
Иерархия исключений
BaseException
├── SystemExit
├── KeyboardInterrupt
├── GeneratorExit
└── Exception
├── StopIteration
├── ArithmeticError
├── LookupError
├── AssertionError
├── AttributeError
├── ImportError
├── RuntimeError
├── ValueError
├── TypeError
└── ... (ещё 50+ встроенных исключений)
BaseException — корень всех исключений
BaseException — это абсолютный корень иерархии. От него наследуются системные исключения и сигналы:
# Что наследуется напрямую от BaseException:
# 1. SystemExit — выход из программы
try:
sys.exit(42)
except BaseException as e:
print(type(e)) # <class 'SystemExit'>
print(e.code) # 42
# 2. KeyboardInterrupt — Ctrl+C
try:
while True:
pass
except BaseException as e:
print(type(e)) # <class 'KeyboardInterrupt'>
# 3. GeneratorExit — завершение генератора
def my_gen():
try:
yield 1
except BaseException as e:
print(type(e)) # <class 'GeneratorExit'>
g = my_gen()
next(g)
g.close()
Exception — исключения приложения
Exception — это базовый класс для всех ошибок приложения, которые нужно обрабатывать:
# Exception ловит ошибки приложения
try:
x = 1 / 0
except Exception as e:
print(type(e)) # <class 'ZeroDivisionError'>
print("Обработано приложением")
# Exception НЕ ловит системные сигналы
try:
raise KeyboardInterrupt()
except Exception as e:
print("Это никогда не выполнится")
except KeyboardInterrupt:
print("KeyboardInterrupt поймана")
Ключевые различия
| Аспект | BaseException | Exception |
|---|---|---|
| Наследуется от | Ничего | BaseException |
| Назначение | Все исключения и сигналы | Ошибки приложения |
| Какие ловит | Всё (SystemExit, KeyboardInterrupt, Exception) | Только ошибки приложения |
| Когда использовать | Редко | В 99% случаев |
| Кастомные классы | Плохая идея наследоваться | Нормально наследоваться |
Практические примеры ошибок
❌ Плохо: ловить BaseException
# Это перехватит даже SystemExit!
try:
user_code()
except BaseException:
print("Перехвачено всё")
# Но SystemExit уже не сработает!
❌ Плохо: ловить голый except
# Deprecated, но ещё используется
try:
data = json.loads(user_input)
except: # ловит ВСЕГО! (включая KeyboardInterrupt)
print("Ошибка")
✅ Хорошо: ловить Exception
try:
data = json.loads(user_input)
except Exception as e: # ловит только ошибки приложения
logger.error(f"JSON error: {e}")
raise # пробросить дальше
except KeyboardInterrupt: # если нужно обработать Ctrl+C отдельно
print("Прерывание пользователем")
Почему не ловить BaseException
# Сценарий: долгоживущий сервис
import time
def server_loop():
try:
while True:
handle_request()
time.sleep(1)
except BaseException: # ПЛОХО!
print("Перехвачено")
# Пользователь нажал Ctrl+C, но программа не завершилась!
# SystemExit был перехвачен и проигнорирован
Правильный способ:
def server_loop():
try:
while True:
handle_request()
time.sleep(1)
except Exception:
print("Ошибка приложения")
except KeyboardInterrupt:
print("Выход по Ctrl+C")
sys.exit(0)
Кастомные исключения
# ✅ Правильно: наследоваться от Exception
class ValidationError(Exception):
pass
class DatabaseError(Exception):
pass
class APIError(Exception):
pass
# ❌ Плохо: наследоваться от BaseException
class BadError(BaseException): # Не делай так!
pass
# Использование
try:
validate_user(data)
except ValidationError as e:
logger.error(f"Validation failed: {e}")
except DatabaseError as e:
logger.error(f"DB error: {e}")
except Exception as e:
logger.error(f"Unexpected error: {e}")
Иерархия кастомных исключений
# Базовое исключение приложения
class AppError(Exception):
pass
# Специфичные ошибки
class UserError(AppError):
pass
class NotFoundError(UserError):
pass
class AuthenticationError(UserError):
pass
class ValidationError(AppError):
pass
# Использование
try:
user = find_user(user_id)
except NotFoundError:
return 404, "User not found"
except ValidationError:
return 400, "Invalid data"
except AppError as e:
return 500, f"Internal error: {e}"
except Exception as e:
logger.error(f"Unexpected: {e}")
return 500, "Critical error"
Обработка специфичных исключений
import json
import requests
# Хорошая обработка разных типов ошибок
try:
response = requests.get(url, timeout=5)
data = response.json()
except requests.Timeout:
logger.error("Request timeout")
except requests.ConnectionError:
logger.error("Connection error")
except json.JSONDecodeError:
logger.error("Invalid JSON response")
except requests.RequestException as e:
logger.error(f"Request error: {e}")
except Exception as e:
logger.error(f"Unexpected error: {e}")
Проверка типов исключений
# Проверить, какое точно исключение
try:
risky_operation()
except Exception as e:
# Проверить тип
if isinstance(e, ValueError):
print("Некорректное значение")
elif isinstance(e, KeyError):
print("Ключ не найден")
else:
print(f"Неизвестная ошибка: {type(e)}")
# Или через __class__
except Exception as e:
if e.__class__.__name__ == "ValueError":
print("Value error")
Повторное выбросение исключения
def log_and_reraise():
try:
risky_operation()
except Exception as e:
# Залогировать и пробросить дальше
logger.error(f"Error: {e}", exc_info=True)
raise # Пробрасывает ТОЖЕ исключение, не новое!
# Или с контекстом
except Exception as e:
logger.error(f"Error: {e}")
raise RuntimeError(f"Failed: {e}") from e # from e сохраняет оригинальный стек
Лучшие практики
# 1. Ловить специфичные исключения
try:
data = database.query(sql)
except DatabaseConnectionError:
# обработать ошибку подключения
pass
except DatabaseQueryError:
# обработать ошибку запроса
pass
# 2. Использовать Exception для неожиданных ошибок
except Exception as e:
logger.error(f"Unexpected error: {e}")
raise
# 3. Никогда не ловить BaseException
# ❌ except BaseException:
# ✅ except Exception:
# 4. Специальная обработка для системных сигналов
try:
main()
except KeyboardInterrupt:
print("Завершение")
sys.exit(0)
except SystemExit as e:
print(f"Выход с кодом {e.code}")
# 5. Документировать выбрасываемые исключения
def divide(a, b):
"""
Raises:
ValueError: если b равно нулю
"""
if b == 0:
raise ValueError("Деление на нуль")
return a / b
Итого
Exception vs BaseException:
- BaseException — абсолютный корень, включает SystemExit и KeyboardInterrupt
- Exception — базовый класс ошибок приложения, это то, что нужно ловить в 99% случаев
- Никогда не лови BaseException в приложениях
- Создавай кастомные исключения наследуясь от Exception
- Лови специфичные исключения перед общими