Типы ошибок и конструкция `try-except` - Python с нуля до Junior: Путь к первой работе в IT - Qpel.AI

Типы ошибок и конструкция `try-except`

Представьте: вы пишете программу, а она вдруг «падает». 💥 Обидно, правда? Ошибки — часть жизни любого разработчика. Они возникают из-за опечаток, неверной логики или неожиданных событий, например, когда нужного файла просто нет.

Важно не только находить и исправлять ошибки, но и предвидеть их. Тогда ваша программа не рухнет при первом сбое, а сможет спокойно на него отреагировать.

Ошибки и исключения: в чем разница?

В Python ошибки делятся на два типа:

  1. Синтаксические ошибки (SyntaxError). Это как грамматические ошибки в языке. Вы нарушили правила Python, и интерпретатор не понимает ваш код. Он останавливает выполнение еще до запуска.

    # Пример синтаксической ошибки
    if True # Ожидается двоеточие после True
        print("Это ошибка")
    

    Такие ошибки легко найти: IDE или сам Python укажут на строку с проблемой.

  2. Исключения (Exceptions). Эти ошибки возникают, когда программа уже запущена, даже если синтаксис идеален. Исключение — это событие, которое нарушает нормальный ход выполнения. Python генерирует его, когда сталкивается с чем-то, что не может обработать.

    # Примеры исключений
    print(10 / 0)       # ZeroDivisionError: деление на ноль
    my_list = [1, 2, 3]
    print(my_list[5])   # IndexError: индекс вне диапазона
    my_dict = {"name": "Alice"}
    print(my_dict["age"]) # KeyError: такого ключа нет
    

    Если исключение не обработать, программа аварийно завершится. Вы увидите сообщение об ошибке — трассировочный вывод или traceback. Он покажет тип исключения и место его возникновения.

Ловим ошибки: try-except

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

Синтаксис простой:

try:
    # Код, который может вызвать исключение
    # Если здесь возникает исключение, выполнение переходит в блок except
except ТипИсключения:
    # Код, который выполняется, если возникло указанное исключение

Давайте разберем пример с делением на ноль:

try:
    numerator = int(input("Введите числитель: "))
    denominator = int(input("Введите знаменатель: "))
    result = numerator / denominator
    print(f"Результат деления: {result}")
except ZeroDivisionError:
    print("Ошибка: Деление на ноль невозможно!")
except ValueError:
    print("Ошибка: Введите только числа!")
print("Программа продолжает работу.")

Что здесь происходит?

  • Блок try пытается выполнить операции ввода и деления.
  • Если пользователь введет 0 в качестве знаменателя, возникнет ZeroDivisionError. Управление перейдет в блок except ZeroDivisionError.
  • Если пользователь введет не число (например, текст), возникнет ValueError. Управление перейдет в блок except ValueError.
  • Если ошибок нет, блоки except пропускаются.
  • Сообщение "Программа продолжает работу." выведется в любом случае, потому что исключения обработаны.

Несколько except блоков

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

try:
    num1 = int(input("Введите первое число: "))
    num2 = int(input("Введите второе число: "))
    res = num1 / num2
    print(f"Результат: {res}")
except ValueError:
    print("Вы ввели некорректные данные. Пожалуйста, введите числа.")
except ZeroDivisionError:
    print("На ноль делить нельзя!")
except Exception as e: # Ловит любое другое исключение
    print(f"Произошла непредвиденная ошибка: {e}")

Важно: Блок except Exception as e: должен быть последним. Почему? Потому что Exception — это базовый класс для всех остальных исключений. Если вы поставите его раньше, он «поймает» все исключения, и более специфичные except блоки никогда не будут достигнуты. Переменная e будет содержать объект исключения, который часто дает полезную информацию об ошибке.

Блоки else и finally

Конструкцию try-except можно дополнить блоками else и finally:

  • else: Код в этом блоке выполняется, если в блоке try не возникло никаких исключений.

    try:
        file_content = open("my_file.txt", "r").read()
    except FileNotFoundError:
        print("Файл не найден.")
    else:
        print("Файл успешно прочитан. Содержимое:")
        print(file_content)
    
  • finally: Код в этом блоке выполняется всегда, независимо от того, возникло исключение или нет, и было ли оно обработано. Это идеальное место для очистки ресурсов (например, закрытия файлов или сетевых соединений).

    file = None
    try:
        file = open("data.txt", "r")
        content = file.read()
        print(content)
    except FileNotFoundError:
        print("Файл data.txt не найден.")
    finally:
        if file: # Проверяем, был ли файл открыт
            file.close()
            print("Файл закрыт.")
    

Практическое задание

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

  1. Запросите у пользователя строку с оценками (например, "5,4,3,5,2").
  2. Попробуйте преобразовать эту строку в список чисел.
  3. Рассчитайте средний балл.
  4. Используйте try-except для обработки следующих ситуаций:
    • ValueError: Если пользователь ввел что-то, что нельзя преобразовать в число (например, "5,четыре,3").
    • ZeroDivisionError: Если пользователь ввел пустую строку или только нечисловые значения, что приведет к пустому списку оценок и делению на ноль при расчете среднего.
    • Любое другое непредвиденное исключение.
  5. Выведите соответствующее сообщение об ошибке или средний балл.
# Ваш код здесь
# Примерная структура:
# try:
#     grades_str = input("Введите оценки через запятую (например, 5,4,3): ")
#     # ... ваш код для обработки и расчета ...
# except ValueError:
#     # ...
# except ZeroDivisionError:
#     # ...
# except Exception as e:
#     # ...

Что дальше?

Теперь вы умеете обрабатывать стандартные исключения. Отлично! В следующем разделе мы пойдем дальше: научимся создавать собственные типы исключений. Это сделает ваш код еще понятнее и контролируемее, особенно в сложных проектах.