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

Может ли интерпретатор перехватывать ошибки?

1.0 Junior🔥 71 комментариев
#Python Core

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

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

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

Может ли интерпретатор перехватывать ошибки?

Да, интерпретатор Python может и должен обрабатывать ошибки через механизм исключений и блоков try-except. Это один из ключевых аспектов обработки ошибок в Python.

Как интерпретатор обрабатывает ошибки

Когда в Python возникает ошибка (исключение), интерпретатор:

  1. Генерирует исключение — создаёт объект исключения
  2. Проходит по стеку вызовов вверх, ища обработчик
  3. Выполняет блок except если найден подходящий обработчик
  4. Завершает программу если обработчика нет
# Ошибка без обработки
x = 1 / 0  # ZeroDivisionError (интерпретатор выбросит исключение)
# Программа останавливается

# С обработкой — интерпретатор ловит ошибку
try:
    x = 1 / 0
except ZeroDivisionError:
    print('Нельзя делить на ноль!')  # Выполнится эта строка
    x = 0

print(x)  # 0 — программа продолжает работу

Try-except блок

Try содержит код, который может вызвать исключение. Except обрабатывает это исключение:

try:
    # Код, который может вызвать исключение
    result = 10 / 0
except ZeroDivisionError:
    # Обработка конкретного типа исключения
    print('Ошибка: деление на ноль')
    result = None

print(f'Результат: {result}')  # Результат: None

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

Все исключения наследуются от BaseException. Понимание иерархии помогает правильно обрабатывать ошибки:

# Иерархия исключений (упрощённо)
# BaseException
#   ├── SystemExit
#   ├── KeyboardInterrupt
#   └── Exception  <- Все пользовательские ошибки
#       ├── StopIteration
#       ├── GeneratorExit
#       ├── ArithmeticError
#       │   ├── ZeroDivisionError
#       │   ├── FloatingPointError
#       │   └── OverflowError
#       ├── LookupError
#       │   ├── IndexError
#       │   └── KeyError
#       ├── ValueError
#       ├── TypeError
#       ├── FileNotFoundError
#       ├── IOError
#       └── ... ещё много

Обработка разных типов ошибок

try:
    # Может вызвать разные ошибки
    data = {'name': 'Alice'}
    x = int('not_a_number')  # ValueError
    
except ValueError as e:
    # Обработка ValueError
    print(f'Ошибка значения: {e}')
    
except IndexError as e:
    # Обработка IndexError
    print(f'Индекс не существует: {e}')
    
except Exception as e:
    # Обработка любого другого исключения
    print(f'Неизвестная ошибка: {e}')
    
else:
    # Выполняется если НЕ было исключений
    print('Ошибок не было!')
    
finally:
    # Выполняется ВСЕГДА (даже при возврате или исключении)
    print('Очистка ресурсов')

Практические примеры

Пример 1: Обработка файловых ошибок

try:
    with open('nonexistent.txt', 'r') as f:
        content = f.read()
except FileNotFoundError:
    print('Файл не найден')
    content = 'Default content'
except PermissionError:
    print('Нет прав доступа')
    content = None
else:
    print('Файл успешно открыт')
finally:
    print('Закрыт файловый дескриптор')

Пример 2: Обработка ошибок при работе с БД

import sqlite3

try:
    connection = sqlite3.connect('database.db')
    cursor = connection.cursor()
    cursor.execute('SELECT * FROM users WHERE id = ?', (123,))
    result = cursor.fetchone()
    
except sqlite3.OperationalError as e:
    print(f'Ошибка базы данных: {e}')
    result = None
    
except sqlite3.DatabaseError as e:
    print(f'Ошибка записи БД: {e}')
    result = None
    
finally:
    if connection:
        connection.close()

Пример 3: Обработка ошибок при парсинге JSON

import json

def parse_json(data):
    try:
        return json.loads(data)
    except json.JSONDecodeError as e:
        print(f'Ошибка парсинга JSON: {e}')
        return {}
    except TypeError:
        print('Данные должны быть строкой')
        return {}

result1 = parse_json('{"name": "Alice"}')  # {'name': 'Alice'}
result2 = parse_json('invalid json')        # {}
result3 = parse_json(123)                   # {}

Выбрасывание собственных исключений

Вы можете выбросить исключение самостоятельно:

def divide(a, b):
    if b == 0:
        raise ValueError('Делитель не может быть нулём')  # Выбросить исключение
    return a / b

try:
    result = divide(10, 0)
except ValueError as e:
    print(f'Ошибка: {e}')  # Ошибка: Делитель не может быть нулём

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

class InsufficientFundsError(Exception):
    """Исключение при недостаточно средств"""
    def __init__(self, balance, amount):
        self.balance = balance
        self.amount = amount
        super().__init__(f'Баланс {balance}, а снять нужно {amount}')

class BankAccount:
    def __init__(self, balance):
        self.balance = balance
    
    def withdraw(self, amount):
        if amount > self.balance:
            raise InsufficientFundsError(self.balance, amount)
        self.balance -= amount
        return self.balance

try:
    account = BankAccount(100)
    account.withdraw(150)  # Выбросит InsufficientFundsError
    
except InsufficientFundsError as e:
    print(f'Ошибка счёта: {e}')
    print(f'Баланс: {e.balance}, Запрос: {e.amount}')

Стек вызовов и отслеживание ошибок

Интерпретатор отслеживает стек вызовов и показывает его при ошибке:

def function_c():
    return 1 / 0  # Ошибка здесь

def function_b():
    return function_c()

def function_a():
    return function_b()

try:
    function_a()
except ZeroDivisionError:
    import traceback
    print('Полный стек вызовов:')
    traceback.print_exc()
    # Выведет:
    # Traceback (most recent call last):
    #   File "...", line XX, in function_a
    #     return function_b()
    #   File "...", line YY, in function_b
    #     return function_c()
    #   File "...", line ZZ, in function_c
    #     return 1 / 0
    # ZeroDivisionError: division by zero

Context managers (with statement)

Context managers автоматически обрабатывают исключения:

# Автоматическое закрытие файла даже при ошибке
try:
    with open('file.txt', 'r') as f:
        data = f.read()
        x = 1 / 0  # Ошибка здесь
except ZeroDivisionError:
    print('Ошибка деления')
# Файл закроется автоматически благодаря __exit__

# Можно создавать свои context managers
from contextlib import contextmanager

@contextmanager
def safe_division():
    try:
        yield
    except ZeroDivisionError:
        print('Перехвачена ошибка деления на ноль')

with safe_division():
    x = 1 / 0  # Будет перехвачена

Цепочка исключений (Exception chaining)

Питон 3 позволяет связывать исключения:

try:
    try:
        x = 1 / 0
    except ZeroDivisionError as e:
        raise ValueError('Ошибка значения') from e  # Сохраняет исходную ошибку
except ValueError as e:
    print(f'Основная ошибка: {e}')
    print(f'Причина: {e.__cause__}')  # Исходная ошибка

Ключевые моменты

  • Да, интерпретатор перехватывает ошибки через try-except
  • Исключения наследуются от BaseException или Exception
  • Try-except-else-finally — полная схема обработки
  • Raise — выбросить исключение самостоятельно
  • Custom exceptions — создавай свои типы ошибок
  • Traceback — показывает стек вызовов при ошибке
  • Context managers — автоматическая обработка ошибок