Найти в Дзене
Код как искусство

Ошибки — это не страшно: учим Python падать красиво

Вы пишете код, запускаете — и вместо результата красный текст в консоли. Знакомо? Многие новички паникуют, видя ошибку. На самом деле ошибки — это не враги, а подсказки. Python говорит: «Я не знаю, что делать дальше, помоги мне». Сегодня научимся не бояться ошибок, а ловить их, обрабатывать и делать программы неубиваемыми. Программа работает последовательно. Когда интерпретатор встречает что-то, что не может выполнить (например, деление на ноль, обращение к несуществующему ключу словаря, попытку открыть отсутствующий файл), он возбуждает исключение. Если исключение не обработано, программа аварийно завершается. Наша задача — предвидеть такие места и корректно реагировать. Python имеет десятки встроенных исключений. Вот те, с которыми вы столкнётесь в первую очередь: Исключение Когда возникает SyntaxError опечатка в коде (не пишется, сразу видно) NameError используется неопределённая переменная TypeError операция с неп
Оглавление

Вы пишете код, запускаете — и вместо результата красный текст в консоли. Знакомо? Многие новички паникуют, видя ошибку. На самом деле ошибки — это не враги, а подсказки. Python говорит: «Я не знаю, что делать дальше, помоги мне». Сегодня научимся не бояться ошибок, а ловить их, обрабатывать и делать программы неубиваемыми.

1. Почему программы падают?

Программа работает последовательно. Когда интерпретатор встречает что-то, что не может выполнить (например, деление на ноль, обращение к несуществующему ключу словаря, попытку открыть отсутствующий файл), он возбуждает исключение. Если исключение не обработано, программа аварийно завершается.

Наша задача — предвидеть такие места и корректно реагировать.

2. Виды исключений (самые частые)

Python имеет десятки встроенных исключений. Вот те, с которыми вы столкнётесь в первую очередь:

Исключение Когда возникает

SyntaxError опечатка в коде (не пишется, сразу видно)

NameError используется неопределённая переменная

TypeError операция с неподходящим типом (например, "2" + 2)

ValueError значение не соответствует ожидаемому (int("abc"))

ZeroDivisionError деление на ноль

IndexError выход за границы списка

KeyError ключ отсутствует в словаре

FileNotFoundError файл не найден

AttributeErrorу объекта нет такого метода/атрибута

3. Конструкция try-except: берём ошибки под контроль

Базовый шаблон:

try:
# код, который может вызвать ошибку
risky_code()
except:
# что делать, если ошибка произошла
handle_error()

Простой пример:

try:
number = int(input("Введите число: "))
print(f"Вы ввели {number}")
except ValueError:
print("Это не число! В следующий раз вводите цифры.")

Теперь программа не упадёт, если пользователь введёт буквы.

4. Ловим конкретные исключения

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

try:
value = int(input("Число: "))
result = 100 / value
print(result)
except ValueError:
print("Это не число.")
except ZeroDivisionError:
print("На ноль делить нельзя.")

Можно объединить несколько типов в кортеж:

except (ValueError, ZeroDivisionError):
print("Ошибка ввода или деления на ноль.")

5. Получаем текст ошибки

Иногда нужно узнать, что именно произошло. Для этого сохраняем исключение в переменную:

try:
with open("data.txt", "r") as f:
content = f.read()
except FileNotFoundError as e:
print(f"Файл не найден. Подробности: {e}")

Переменная e содержит сообщение об ошибке, которое можно вывести или записать в лог.

6. Блоки else и finally

  • else — выполняется, если в try не возникло исключений.
  • finally — выполняется всегда, даже если ошибка была. Используется для освобождения ресурсов (закрытие файлов, соединений).

try:
file = open("data.txt", "r")
except FileNotFoundError:
print("Файл не найден, создаю новый.")
file = open("data.txt", "w")
else:
print("Файл успешно открыт для чтения.")
finally:
file.close()
print("Файл закрыт.")

7. Генерация собственных исключений (raise)

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

def divide(a, b):
if b == 0:
raise ValueError("Деление на ноль запрещено.")
return a / b

try:
result = divide(10, 0)
except ValueError as e:
print(e)

Можно создавать и собственные классы исключений, но для начала достаточно встроенных.

8. Типичные ошибки новичков

❌ Слишком широкий except

try:
# какой-то код
except:
pass # молча проглатываем ВСЕ ошибки

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

❌ Вложенные try-except без необходимости

Можно обойтись одним блоком, обрабатывая несколько исключений.

❌ Игнорирование ошибок при работе с файлами

Не все файлы открываются. Всегда предусматривайте FileNotFoundError, PermissionError.

❌ Неправильный порядок обработки

Если вы ловите родительское исключение (например, Exception) до дочернего, дочернее никогда не сработает.

9. Живой пример: улучшаем игру «Угадай число» с надёжной защитой

Вернёмся к игре из второй статьи. Усовершенствуем обработку ошибок: добавим защиту от ввода нечисловых значений, от деления на ноль (хотя в игре его нет, но покажем принцип), а также от неожиданных ситуаций.

import random

def get_random_number(min_val, max_val):
return random.randint(min_val, max_val)

def get_user_guess():
while True:
try:
guess = int(input("Твой вариант: "))
return guess
except ValueError:
print("Ошибка: нужно ввести целое число. Попробуй ещё раз.")
except KeyboardInterrupt:
print("\nИгра прервана пользователем.")
exit(0)
except Exception as e:
print(f"Неожиданная ошибка: {e}")
print("Попробуйте снова.")

def check_guess(guess, secret):
if guess < secret:
return "Загаданное число БОЛЬШЕ.", False
elif guess > secret:
return "Загаданное число МЕНЬШЕ.", False
else:
return f"Поздравляю! Ты угадал число {secret}!", True

def play_game():
secret = get_random_number(1, 100)
print("Я загадал число от 1 до 100. Попробуй угадать!")

while True:
guess = get_user_guess()
message, is_correct = check_guess(guess, secret)
print(message)
if is_correct:
break

if __name__ == "__main__":
play_game()

Теперь игра не упадёт ни при каком вводе. Если пользователь нажмёт Ctrl+C — завершится корректно.

10. Логирование ошибок вместо print

Для серьёзных проектов лучше использовать модуль logging:

import logging

logging.basicConfig(level=logging.ERROR, filename="errors.log")

try:
risky_operation()
except Exception as e:
logging.error(f"Произошла ошибка: {e}", exc_info=True)

Это сохранит стек вызовов в файл, и вы сможете анализировать проблемы позже.

Заключение

Обработка исключений превращает хрупкие скрипты в надёжные программы. Теперь вы знаете:

  • как перехватывать ошибки с помощью try-except,
  • как различать типы исключений,
  • как использовать else и finally,
  • как генерировать свои ошибки через raise.

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

Пишите в комментариях, с какими ошибками вы чаще всего сталкивались и как их победили. Делимся опытом!