Исключения в Python: конструкция try except и её применение

Раздел: Ошибки -> Обработка исключений

Основы обработки исключений с try except

При выполнении программы на Python могут возникать ошибки времени выполнения, называемые исключениями. Чтобы программа не завершалась аварийно, используется конструкция try except. Она позволяет перехватывать исключения и выполнять альтернативные действия.

Базовый синтаксис:

try:
    # Код, который может вызвать исключение
    risky_operation()
except ExceptionType:
    # Действия при возникновении исключения
    handle_error()

Python ignore error (игнорирование ошибок python)

Если в блоке try возникает исключение, указанное после except, выполнение переходит в блок except. Если исключение не возникает, блок except пропускается.

Типичные проблемы:

  • Слишком широкий перехват (голый except:) скрывает неожиданные ошибки, такие как KeyboardInterrupt или SystemExit.
  • Забывают указать тип исключения, что делает код небезопасным.
  • Пустой блок exceptpass) может замаскировать серьёзные проблемы.

Как перехватить только определённое исключение?

Указывайте конкретный класс исключения после except:

try:
    value = int(input("Введите число: "))
except ValueError:
    print("Ошибка: введено не число")

Python exception (исключения в python)

Распространённая ошибка:

Перехват более общего исключения, чем нужно. Например, except Exception: обработает и ValueError, и TypeError, и другие, что может скрыть логические ошибки.

Как обработать несколько разных исключений?

Можно указать несколько блоков except или перечислить исключения в кортеже:

try:
    result = 10 / int(input("Делитель: "))
    print(result)
except ZeroDivisionError:
    print("Деление на ноль")
except ValueError:
    print("Неверный ввод")

исключения в python инструкция try except (обработка исключений try except в python)

# Или одним блоком
try:
    result = 10 / int(input("Делитель: "))
except (ZeroDivisionError, ValueError) as e:
    print(f"Ошибка: {e}")

Python errno (обработка ошибки errno в python)

Проблема:

Если исключения перехватываются кортежем, удаётся обрабатывать их одинаково, но теряется возможность разного реагирования.

Как выполнить код, если исключения не было?

Блок else выполняется, только если в try не возникло исключения:

try:
    number = int(input("Введите число: "))
except ValueError:
    print("Ошибка преобразования")
else:
    print(f"Вы ввели {number}")

Python get traceback (получение трассировки стека в python)

Этот блок позволяет отделить основной успешный сценарий от обработки ошибок.

Как гарантировать выполнение очистки ресурсов?

Блок finally выполняется всегда, независимо от того, было исключение или нет. Он используется для закрытия файлов, освобождения соединений и т.п.:

try:
    file = open("data.txt")
    data = file.read()
except FileNotFoundError:
    print("Файл не найден")
finally:
    file.close()

Важно:

Если в finally возникает исключение, оно заменит предыдущее. Следует избегать сложного кода в finally.

Типичная ошибка:

Попытка использовать finally для возврата значения из функции; finally переопределит возвращаемое значение.

Как повторно возбудить исключение?

Используйте raise без аргументов внутри except, чтобы передать исключение дальше:

try:
    func_that_fails()
except ValueError:
    log_error()
    raise   # исходное исключение поднимается выше

Также можно создать новое исключение: raise NewException("Описание").

Как создать собственное исключение?

Определите класс, наследующий от Exception:

class MyError(Exception):
    def __init__(self, message):
        super().__init__(message)

try:
    raise MyError("Произошла моя ошибка")
except MyError as e:
    print(e)

Проблема:

Если не вызвать super().__init__(), сообщение об ошибке может не передаться.

Как перехватывать исключения во вложенных блоках?

Внутренний try может обрабатывать свои ошибки, а внешний - более общие:

try:
    # внешний блок
    try:
        x = int("abc")
    except ValueError:
        print("Внутренняя обработка")
        raise   # передаём во внешний блок
    except TypeError:
        print("Тип не тот")
except Exception as e:
    print(f"Внешний блок: {e}")

Важно понимать, что исключение, не обработанное во внутреннем блоке, всплывает во внешний.

Заключение:

Грамотное использование try except делает программы устойчивыми к ошибкам. Следует избегать голого except:, всегда указывать конкретные типы исключений и применять else и finally для чистоты кода.

Расширенные примеры использования try except

Ниже приведены более сложные сценарии обработки исключений с подробными пояснениями.

Пример 1. Обработка ошибок ввода и деления с логированием

Пример
import logging

logging.basicConfig(level=logging.ERROR)

def safe_divide():
    try:
        numerator = float(input("Введите делимое: "))
        denominator = float(input("Введите делитель: "))
        result = numerator / denominator
    except ValueError:
        logging.error("Не удалось преобразовать строку в число")
        print("Ошибка: введите корректные числа")
    except ZeroDivisionError:
        logging.error("Попытка деления на ноль")
        print("Ошибка: деление на ноль невозможно")
    else:
        print(f"Результат: {result:.2f}")
    finally:
        print("Завершение операции")

safe_divide()

Пояснение: В этом примере используются все четыре ключевых слова: try, except (с двумя разными типами), else и finally. Логирование помогает отслеживать ошибки в продуктивной среде.

Пример 2. Собственное исключение для бизнес-логики

Пример
class InsufficientFundsError(Exception):
    def __init__(self, balance, amount):
        self.balance = balance
        self.amount = amount
        super().__init__(f"Недостаточно средств: баланс {balance}, запрос {amount}")

def withdraw(balance, amount):
    if amount > balance:
        raise InsufficientFundsError(balance, amount)
    return balance - amount

try:
    new_balance = withdraw(100, 150)
except InsufficientFundsError as e:
    print("Ошибка:", e)
    # Можно принять решение, например, запросить меньшую сумму
else:
    print("Новый баланс:", new_balance)

Результат: Ошибка: Недостаточно средств: баланс 100, запрос 150

Этот пример демонстрирует создание и использование пользовательского исключения с дополнительными атрибутами.

Пример 3. Вложенные блоки try и освобождение ресурсов

Пример
import socket

sock = None
try:
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    try:
        sock.connect(("example.com", 80))
        sock.sendall(b"GET / HTTP/1.1\r\nHost: example.com\r\n\r\n")
        response = sock.recv(4096)
        print(response[:200])
    except socket.error as sock_err:
        print(f"Сетевая ошибка: {sock_err}")
    finally:
        if sock:
            sock.close()
            print("Сокет закрыт")
except Exception as e:
    print(f"Не удалось создать сокет: {e}")

Пояснение: Внешний try обрабатывает ошибки создания сокета, внутренний - ошибки соединения и передачи. finally гарантирует закрытие сокета даже при возникновении ошибки.

Пример 4. Цепочка исключений (raise from)

Пример
def parse_data(data):
    try:
        number = int(data)
    except ValueError as exc:
        raise RuntimeError("Не удалось распарсить данные") from exc

try:
    parse_data("abc")
except RuntimeError as e:
    print(f"Ошибка: {e}")
    print(f"Исходное исключение: {e.__cause__}")

Результат: Ошибка: Не удалось распарсить данные
Исходное исключение: invalid literal for int() with base 10: 'abc'

Конструкция raise ... from exc сохраняет цепочку исключений, что облегчает отладку.

Пример 5. Обработка исключений в асинхронном коде

Пример
import asyncio

async def async_worker():
    try:
        await asyncio.sleep(2)
        raise ValueError("Асинхронная ошибка")
    except ValueError as e:
        print(f"Перехвачено: {e}")
    finally:
        print("Завершение асинхронной задачи")

asyncio.run(async_worker())

Результат: Перехвачено: Асинхронная ошибка
Завершение асинхронной задачи

В асинхронных функциях try except работает так же, как и в синхронных.

Обработка исключений try except в Python - comments

En
исключения в python инструкция try except (python)