← Назад к вопросам

В чем разница между ошибкой и исключением?

1.3 Junior🔥 231 комментариев
#Python Core

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Разница между ошибками и исключениями в Python

В Python концепции "ошибка" и "исключение" связаны, но имеют различия. Оба являются подклассами встроенного класса BaseException, но используются для разных целей и обрабатываются по-разному.

Иерархия исключений в Python

BaseException
├── SystemExit      # Выход из программы (sys.exit())
├── KeyboardInterrupt  # Ctrl+C
├── GeneratorExit   # Выход из генератора
└── Exception       # Базовый класс для всех обычных исключений
    ├── StopIteration  # Конец итератора
    ├── ArithmeticError  # Математические ошибки
    │   ├── ZeroDivisionError
    │   ├── FloatingPointError
    │   └── OverflowError
    ├── LookupError  # Ошибки доступа
    │   ├── IndexError
    │   └── KeyError
    ├── TypeError    # Неверный тип данных
    ├── ValueError   # Неверное значение
    ├── AttributeError  # Нет атрибута
    ├── NameError    # Переменная не определена
    ├── RuntimeError # Ошибки выполнения
    └── ... (и множество других)

Определение: Ошибки (Errors)

Ошибки — это исключения, которые обычно не следует обрабатывать в пользовательском коде. Они указывают на серьёзные проблемы в системе или среде выполнения. Примеры:

  • SystemExit — явный выход программы
  • KeyboardInterrupt — прерывание пользователем (Ctrl+C)
  • GeneratorExit — выход из генератора
  • MemoryError — недостаточно памяти
  • StackOverflowError — переполнение стека
  • ImportError — ошибка импорта модуля

Определение: Исключения (Exceptions)

Исключения — это события, которые изменяют нормальный ход выполнения программы. Они могут и должны быть обработаны в пользовательском коде. Примеры:

  • ValueError — неверное значение
  • TypeError — неверный тип данных
  • KeyError — ключ не найден в словаре
  • IndexError — индекс вне границ списка
  • FileNotFoundError — файл не найден
  • ConnectionError — ошибка соединения

Практическое различие

# ❌ Ошибка - обрабатывать НЕ нужно (нет смысла)
try:
    sys.exit(0)  # SystemExit
except SystemExit:
    pass  # Это плохая практика - программа должна завершиться


# ✅ Исключение - обрабатываем (имеет смысл)
try:
    result = 10 / 0  # ZeroDivisionError
except ZeroDivisionError:
    print("Нельзя делить на ноль!")
    result = 0  # Обработали ошибку и продолжили


# ❌ Неправильно - ловим ошибку системы
try:
    # Кто-то случайно удалил файл БД
    with open(/data/important.db) as f:
        data = f.read()
except FileNotFoundError:
    # Это исключение, его МОЖНО обрабатывать
    pass


# ✅ Правильно - ловим системную ошибку только когда нужно
try:
    import critical_module
except ImportError as e:
    # Предупредим, но программа может работать без этого модуля
    print(f"Warning: {e}")

Различия в таблице

АспектОшибкаИсключение
Наследуется отError (подкласс BaseException)Exception (подкласс BaseException)
ОбрабатываемостьНе должна обрабатыватьсяДолжна обрабатываться
ПричинаСерьёзные проблемы в системеПредсказуемые проблемы в коде
ПримерыSystemExit, KeyboardInterruptValueError, TypeError
Обычный блок try-exceptexcept Exception их не ловитexcept Exception их ловит

Частая ошибка: ловить слишком много

# ❌ Плохо - ловим ВСЁ, включая ошибки системы
try:
    user_input = input("Введите число: ")
    number = int(user_input)
    result = 100 / number
except:  # Bare except ловит даже SystemExit!
    print("Что-то пошло не так")


# ✅ Хорошо - ловим только ожидаемые исключения
try:
    user_input = input("Введите число: ")
    number = int(user_input)
    result = 100 / number
except (ValueError, ZeroDivisionError) as e:
    print(f"Некорректный ввод: {e}")


# ✅ Ещё лучше - обрабатываем разные случаи по-разному
try:
    user_input = input("Введите число: ")
    number = int(user_input)
    result = 100 / number
except ValueError:
    print("Пожалуйста, введите целое число")
except ZeroDivisionError:
    print("Невозможно делить на ноль")
except Exception as e:  # Только для неожиданных исключений
    print(f"Непредвиденная ошибка: {e}")
    raise  # Пробросим дальше

Создание собственных исключений

# ✅ Пользовательское исключение (наследуется от Exception)
class InsufficientFundsError(Exception):
    """Исключение для случая, когда недостаточно средств."""
    pass


class AccountError(Exception):
    """Базовое исключение для всех ошибок аккаунта."""
    pass


class NegativeBalanceError(AccountError):
    """Специфическое исключение при отрицательном балансе."""
    pass


class BankAccount:
    def __init__(self, balance: float):
        self.balance = balance
    
    def withdraw(self, amount: float):
        if amount > self.balance:
            raise InsufficientFundsError(
                f"Недостаточно средств. Требуется {amount}, "
                f"доступно {self.balance}"
            )
        self.balance -= amount
    
    def set_balance(self, amount: float):
        if amount < 0:
            raise NegativeBalanceError(
                "Баланс не может быть отрицательным"
            )
        self.balance = amount


# Использование
try:
    account = BankAccount(100)
    account.withdraw(150)
except InsufficientFundsError as e:
    print(f"Ошибка: {e}")

Best Practices

# ✅ Принцип EAFP (Easier to Ask for Forgiveness than Permission)
# В Python предпочитают ловить исключения, чем проверять условия

# Плохо - Pythonic не нужно проверять наличие ключа
if key in my_dict:
    value = my_dict[key]


# Хорошо - просто ловим исключение если ключа нет
try:
    value = my_dict[key]
except KeyError:
    value = None  # или дефолт значение

Понимание разницы между ошибками и исключениями критично для написания надёжного и правильно обрабатывающего ошибки кода.

В чем разница между ошибкой и исключением? | PrepBro