⚖️ Старый и современный подход

⚡ Различия в двух словах

Из источника: базовые try/except с выводом ошибок через print.

Современная практика: ловим только конкретные исключения, используем guard clauses, логируем ошибки через logging, освобождаем ресурсы через with.

Вывод: не подавляйте ошибки и не ловите всё подряд — это мешает отладке.

📜 Как показано в исходном материале

Исходная лекция использует простые конструкции try/except с выводом сообщений через print:

# из исходника
try:
    result = 10 / 0
except ZeroDivisionError:
    print("Ошибка: деление на ноль!")

Этот код корректен и понятен, но в реальных программах его стоит дополнить логированием и более точной обработкой.

❌ Что можно улучшить

  • Общий except Exception: или «голый» except: перехватывают слишком много, включая системные исключения.
  • Простой print не сохраняет историю ошибок — в production важны логи.
  • Блок try часто содержит лишний код, который не должен обрабатываться как ошибка.
  • Ресурсы (файлы, соединения) лучше освобождать через with, а не вручную в finally.

✅ Рекомендуемый современный вариант

# modern_safe_divide.py
import logging

logging.basicConfig(
    filename="errors.log",
    format="%(asctime)s - %(filename)s - %(lineno)d - %(levelname)s - %(message)s",
    level=logging.ERROR,
)


def safe_divide(a: float, b: float) -> float:
    if b == 0:
        raise ValueError("Делитель не может быть нулём")
    return a / b


try:
    dividend = float(input("Введите делимое: "))
    divisor = float(input("Введите делитель: "))
    result = safe_divide(dividend, divisor)
except ValueError as e:
    logging.error(f"Ошибка: {e}")
    print(f"Ошибка: {e}")
else:
    print(f"Результат: {result}")

Что улучшилось:

  • Guard clause внутри функции явно проверяет делитель.
  • Конкретное исключение ValueError вместо общего Exception.
  • Логирование сохраняет ошибку в файл.
  • else отделяет успешный сценарий от обработки ошибок.

Современный подход к файлам

⚠️ Проверить по документации: менеджер контекста with для работы с файлами не разбирается в исходной лекции, но является рекомендуемым способом гарантировать закрытие ресурса.
# modern_file_handling.py
# Читаем числа из файла и суммируем их.
filename = "numbers.txt"
total = 0

try:
    with open(filename, "r", encoding="utf-8") as file:
        for line in file:
            total += float(line.strip())
except FileNotFoundError:
    print(f"Файл {filename} не найден.")
except ValueError as e:
    print(f"Некорректная строка: {e}")
else:
    print(f"Сумма: {total}")

Конструкция with автоматически закрывает файл даже при исключении, заменяя try/finally.

EAFP вместо LBYL

В Python часто предпочитают стиль EAFP (Easier to Ask for Forgiveness than Permission) — проще попросить прощения, чем разрешения. Вместо множества предварительных проверок делаем действие и ловим ожидаемое исключение:

# eafp_example.py
info = {"a": 1}

# LBYL: много проверок
if "b" in info:
    print(info["b"])
else:
    print("Ключа b нет")

# EAFP: проще и понятнее
try:
    print(info["b"])
except KeyError:
    print("Ключа b нет")

Оба подхода допустимы, но в Python EAFP часто читается лучше и работает быстрее для встроенных типов.

🕰️ Когда старый подход ещё можно встретить

Учебные примеры и быстрые скрипты часто используют print и простые try/except. Это нормально для демонстрации, но в домашних заданиях и реальных проектах стоит применять конкретные исключения, логирование и guard clauses.