Модуль 22

Обробка помилок та exceptions

Ось готовий урок, створений спеціально для тебе у стилі David Malan. Вмикай уяву, ніби ти зараз в аудиторії Sanders Theatre в Гарварді!


🎓 CS50: Обробка помилок та Exceptions (Винятки)

Привіт, друзі! Це CS50! 👋

1. 🔥 Вступ: Коли все йде шкереберть

Уявіть собі ситуацію. Ви приходите в улюблену кав’ярню і замовляєте лате на вівсяному молоці. Але в бариста закінчилося вівсяне молоко.

Якби ця кав’ярня працювала як погано написана програма, бариста просто завмер би на місці, втупився в стіну, і вся черга за вами чекала б вічність. Заклад зачинено. Fatal Error. 💥

Але в реальному житті (і в хорошому коді) відбувається інакше. Бариста каже: "Вибачте, вівсяного немає. Може, мигдальне?" Він повідомляє про проблему, і процес продовжується.

У програмуванні це і є Exception (Виняток).

Питання до вас: Чому ми дозволяємо нашим програмам "падати" від найменшої помилки, якщо навіть кавомашина вміє писати "Check Water Tank"?

Без обробки помилок ваш код — це кришталева ваза. Один необережний рух користувача (наприклад, введення літер замість цифр) — і все розбивається вщент. Сьогодні ми навчимося робити наш код куленепробивним.


2. 🧠 Теоретична база: Що там "під капотом"?

Давайте зазирнемо всередину.

Коли комп'ютер виконує ваш код, він йде рядок за рядком. Але коли стається щось непередбачуване (наприклад, ділення на нуль або спроба відкрити файл, якого не існує), процесор не знає, як обчислити наступний крок.

У цей момент система "викидає виняток" (throws an exception).

Уявіть це як естафету з гарячою картоплею 🥔: 1. Функція, де сталася помилка, кричить: "Я не знаю, що робити!" і кидає цю "картоплю" (об'єкт помилки) тій функції, яка її викликала. 2. Якщо та функція теж не знає, що робити, вона кидає її ще вище. 3. Якщо "картопля" долітає до головного входу в програму і ніхто її не зловив — програма аварійно завершується (crashes).

Ключові гравці:

  • try (Спробуй): Ви кажете комп'ютеру: "Слухай, спробуй виконати цей код. Я знаю, що він небезпечний, але спробуй".
  • catch / except (Злови): Це ваша страховка. "Якщо у блоці try станеться біда, не падай! Стрибай сюди, я знаю, що робити".
  • finally (Нарешті): Код, який виконається завжди, незалежно від того, була помилка чи ні (наприклад, помити чашку після кави).

Що треба запам'ятати залізно: Обробка помилок — це не про виправлення багів у коді. Це про те, як ваша програма реагує на непередбачувані умови зовнішнього світу.


3. 🧪 Приклади: Від "Ой" до "Професіонала"

Ми будемо використовувати синтаксис, схожий на Python (він найчитабельніший), але логіка однакова для Java, C#, JS тощо.

Рівень 1: Класика жанру (Ділення на нуль)

Уявіть простий калькулятор.

# Небезпечний код 😱
x = int(input("Введіть число: "))
y = int(input("Введіть дільник: "))
result = x / y
print(f"Результат: {result}")

🛑 Питання: Що станеться, якщо я введу 0 замість y? Правильно. ZeroDivisionError. Програма "вмре", і користувач побачить страшний червоний текст.

Рівень 2: Додаємо захист

# Безпечний код 🛡️
try:
    x = int(input("Введіть число: "))
    y = int(input("Введіть дільник: "))
    result = x / y
    print(f"Результат: {result}")
except ZeroDivisionError:
    print("Гей! На нуль ділити не можна! Спробуй ще раз.")
except ValueError:
    print("Я просив число, а не слово!")

Що тут відбулося? Ми передбачили конкретні проблеми. Якщо користувач введе "нуль", ми його ввічливо попередимо. Програма не впала, вона продовжила роботу.

Рівень 3: Реальний кейс (Файлова система)

Уявіть, що ви пишете програму, яка читає конфігурацію сервера з файлу.

def read_config(filename):
    file = None
    try:
        file = open(filename, "r")
        data = file.read()
        return data
    except FileNotFoundError:
        print("🚨 Увага: Файл налаштувань не знайдено. Завантажую стандартні налаштування.")
        return "DEFAULT_SETTINGS"
    finally:
        # Цей блок виконається ЗАВЖДИ.
        # Навіть якщо файл не знайдено, або якщо він прочитався успішно.
        if file:
            file.close()
            print("🔒 Файл закрито.")

Чому це круто? Ми використали finally. Уявіть, що помилка сталася посеред читання файлу. Без finally файл міг би залишитися "відкритим" у пам'яті, блокуючи доступ іншим програмам. Finally — це як прибирання робочого місця за собою.


4. 🛠 Практична частина

Час забруднити руки! 💻

Завдання 1. "Банкомат" Напиши код, який запитує у користувача суму для зняття. * Якщо сума від'ємна — "викинь" помилку (raise exception). * Якщо сума більша за баланс — іншу помилку. * Огорни це в try/except і виведи зрозумілі повідомлення.

Завдання 2. "Індекс" Створи список із трьох фруктів: ['apple', 'banana', 'cherry']. Попроси користувача ввести номер елемента, який він хоче отримати. * Оброби помилку, якщо він введе число 10 (IndexError). * Оброби помилку, якщо він введе "привіт" замість числа.

Завдання 3. "Детектив" Ви маєте код: value = database["user_age"] Але ви не знаєте, чи є ключ "user_age" в базі. Напишіть конструкцію, яка спробує дістати значення, а якщо ключа немає — встановить value = 18 за замовчуванням.

Завдання 4. Міні-кейс Ви розробляєте форму реєстрації. Користувач вводить вік. Придумайте свій власний тип помилки (наприклад, TooYoungError), якщо вік менше 13 років, і обробіть його.

Питання "А що, якщо...": А що, якщо в блоці catch (або except) теж станеться помилка? Хто її зловить? (Спойлер: це називається вкладені try-catch, подумайте про це як про матрьошку).


5. 💡 Мислення як у розробника

Ось де різниця між новачком і профі.

🚫 Помилка новачка: "Pokemon Exception Handling"

try:
    # якийсь код
except:
    pass  # Просто мовчимо

Це називається "Gotta Catch 'Em All" (спіймати їх усіх). Ви ловите абсолютно всі помилки і... нічого не робите. Чому це погано? Якщо ваша програма зламається через серйозну проблему (наприклад, закінчилася пам'ять), ви про це навіть не дізнаєтесь. Програма буде працювати неправильно, але мовчки. Це нічний жах для налагодження.

Як думає сеньйор: 1. Лови конкретно: Лови тільки ті помилки, які ти очікуєш (FileNotFound, ValueError). 2. Fail Fast (Падай швидко): Краще програма впаде одразу і голосно повідомить про помилку, ніж працюватиме з пошкодженими даними. 3. Логи — це все: У реальному продакшені ми не пишемо print(). Ми пишемо в лог-файл, щоб потім адмін міг подивитися, чому о 3-й ночі впав сервер.


6. 🧩 Підсумок

Отже, що ми маємо?

  1. Помилки — це нормально. Це не провал, це частина процесу.
  2. try/except — це ваш бронежилет.
  3. Не ковтайте помилки мовчки. Будьте чесними з користувачем (і з собою).

Тепер ви вмієте: Писати код, який не розвалюється від першого ж "неправильного" кліку мишкою. Ви керуєте хаосом, а не хаос вами.

🔍 Тизер наступного уроку: Тепер, коли наш код надійний, виникає питання: а де зберігати всі ці дані, щоб вони не зникали після вимкнення комп'ютера? Файли — це добре, але як щодо мільйонів записів? Наступного разу ми поговоримо про Бази Даних і SQL. 🗄️

This was CS50. Побачимось!