Исключения в 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. - Забывают указать тип исключения, что делает код небезопасным.
- Пустой блок
except(сpass) может замаскировать серьёзные проблемы.
Как перехватить только определённое исключение?
Указывайте конкретный класс исключения после 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 работает так же, как и в синхронных.