Python Try Except: пояснюється на прикладах

Конструкція `try-except` в Python дозволяє коректно обробляти виняткові ситуації, уникаючи аварійного завершення програми.

Застосування механізму обробки винятків робить ваш програмний код стійкішим до збоїв. У цій статті ми розглянемо принципи обробки винятків, типові ситуації, де це необхідно, і, як бонус, навчимося їх ініціювати.

Що таке обробка винятків?

Винятки – це аномалії або помилки, які можуть виникнути під час виконання програми. Якщо їх не обробити, це може призвести до її аварійного завершення. Отже, обробка винятків – це метод керування цими винятковими ситуаціями для забезпечення стабільної роботи програми.

Розглянемо приклад, щоб краще зрозуміти, що таке виняток:

user_input = input("Введіть число: ")
num = int(user_input)
print("Ваше число, помножене на два:", num * 2)

На перший погляд, цей код виглядає безпроблемно. Він отримує вхідні дані від користувача, перетворює їх на ціле число та виводить результат подвоєння.

Програма працює бездоганно, якщо введено число, наприклад, 5. Нижче ви можете побачити приклад виконання:

Але уявіть, що ви знову запускаєте ту ж програму, але цього разу вводите текст “привіт”. Програма зазнає краху. Рядок “привіт” неможливо перетворити на ціле число, що призводить до виникнення винятку та аварійного завершення програми.

Чому виникають винятки і чому їх потрібно обробляти?

Винятки виникають через те, що при написанні коду програми часто поділяються на функції. Ці функції потім викликаються для виконання різних дій.

У наведеному прикладі ми спочатку викликали функцію `input` для отримання даних від користувача, потім функцію `int` для перетворення введеного рядка на ціле число, і нарешті, функцію `print` для виведення результату.

Проте, під час виконання функцій можуть виникати ситуації, коли вони стикаються з помилками, які не можуть самостійно виправити. У такому разі ці функції мають припинити свою роботу та сигналізувати про виникнення помилки, генеруючи винятки.

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

Отже, винятки – це механізм комунікації, який дозволяє викликаній функції повідомити код, що її викликав, про проблему. Адекватна реакція на ці винятки – це і є суть обробки винятків.

Різні типи винятків

Важливо розуміти, що не всі винятки однакові. Існують різні типи винятків, які відповідають різним типам помилок. Наприклад, спроба поділити число на нуль призведе до виникнення помилки `ZeroDivisionError`. Помилка `TypeError` виникає, коли ви намагаєтеся виконати операцію з невідповідним типом даних. Повний перелік типів винятків доступний у документації Python.

Як обробляти винятки

Як вже зазначалося, винятки – це сигнали, що виникають у функціях, які ми викликаємо. Тому наш код повинен вміти перехоплювати ці сигнали та реагувати на них. Для коректної обробки винятків у Python використовується конструкція `try-except`. Основна структура цієї конструкції виглядає наступним чином:

try:
    # Код, який може спричинити виняток
except:
    # Код, який виконається, якщо виникне виняток
finally:
    # Код, який виконається у будь-якому випадку

Як ви бачите, конструкція складається з трьох ключових слів, які ми розглянемо далі:

`try`

Ключове слово `try` позначає початок блоку коду, який може спричинити виняток. Інтерпретатор Python спробує виконати код у цьому блоці. Якщо під час виконання виникне виняток, виконання коду в блоці `try` негайно припиниться, і програма перейде до виконання коду в блоці `except`.

`except`

Ключове слово `except` визначає блок коду, який буде виконано у разі виникнення винятку під час виконання коду в блоці `try`. Можна визначити декілька блоків `except` для різних типів винятків. Ми розглянемо це далі.

`finally`

Ключове слово `finally` – останнє, що використовується в конструкції `try-except`. Воно визначає блок коду, який буде виконаний у будь-якому випадку, незалежно від того, чи виник виняток, чи ні.

Приклад

Розглянемо приклад, як можна використовувати ці ключові слова для обробки винятків. Модифікуємо попередній приклад:

try:
    user_input = input("Введіть число: ")
    num = int(user_input)
    print("Ваше число, помножене на два:", num * 2)
except:
    print("Щось пішло не так")
finally:
    print("Цей код виконається у будь-якому разі")

Якщо ви запустите цей код з коректним введенням, наприклад, 5, ви отримаєте такий результат:

А якщо ви введете “привіт”, то отримаєте наступне:

Отже, коли під час виконання коду в блоці `try` не виникає винятків, комп’ютер переходить до блоку `finally`. Якщо ж під час виконання коду в блоці `try` виникає виняток, комп’ютер переходить до блоку `except`, а потім до блоку `finally`.

Ви також можете обробляти винятки конкретних типів. Наприклад, якщо ви хочете обробити винятки `ValueError` та `KeyboardInterrupt` окремо, ви можете модифікувати попередній код таким чином:

try:
    user_input = input("Введіть число: ")
    num = int(user_input)
    print("Ваше число, помножене на два:", num * 2)
except ValueError:
    print("Значення неможливо перетворити на ціле число")
except KeyboardInterrupt:
    print("Отримано переривання клавіатури")
except:
    print("Універсальний блок обробки винятків")
finally:
    print("Цей код виконається у будь-якому разі")

У цьому коді у нас є три блоки `except`. Перший блок обробляє виключно винятки `ValueError`, другий – винятки `KeyboardInterrupt`. Останній блок не має вказаного типу винятку, тому він обробляє всі інші винятки, які не були перехоплені першими двома блоками.

Запустивши цей код, ви отримаєте наступні результати:

Коли виникає виняток, ви можете отримати додаткову інформацію про нього в об’єкті винятку. Для доступу до об’єкта винятку використовується ключове слово `as`. Ось як це працює:

try:
    user_input = input("Введіть число: ")
    num = int(user_input)
    print("Ваше число, помножене на два:", num * 2)
except ValueError as e:
    print("Помилка значення:", e)
except KeyboardInterrupt as e:
    print("Переривання клавіатури:", e)
except Exception as e:
    print("Інший виняток:", e)

Як ініціювати винятки

До цього моменту ми розглядали винятки, які генеруються іншими функціями. Однак ви можете ініціювати винятки у своєму власному коді. Для цього використовується ключове слово `raise`. Також потрібно вказати клас, який представляє тип винятку, та повідомлення, що пояснює причину виникнення.

У наступному прикладі ми використовуємо клас `Exception` для ініціації загального винятку. Повідомлення передається конструктору класу:

raise Exception('Щось пішло не так')

Якщо ви запустите цей фрагмент коду як програму, ви отримаєте подібний результат:

Ви можете ініціювати і винятки інших типів. Наприклад, ви можете викликати виняток `TypeError`, якщо значення має неправильний тип даних:

def double(x):
    if isinstance(x, int):
        return x * 2
    else:
        raise TypeError('x повинен бути цілим числом')

Або, якщо значення виходить за допустимі межі, ви можете ініціювати виняток `ValueError`:

def say_hello(name):
    if name == '':
        raise ValueError('Значення поза межами допустимого діапазону')
    else:
        print('Привіт,', name)

Ви також можете створити свої власні типи винятків, створивши підклас класу `Exception`. Ось приклад:

class InvalidHTTPMethod(Exception):
    pass

У цьому прикладі ми створили клас `InvalidHTTPMethod`, який наслідує клас `Exception`. Тепер ми можемо використовувати його для ініціації винятків:

raise InvalidHTTPMethod('Метод повинен бути GET або POST')

Поширені випадки використання обробки винятків

Обробка винятків використовується в багатьох ситуаціях. Попередній приклад показав, як вона використовується для обробки винятків при введенні даних користувачем. У цьому розділі ми розглянемо ще два випадки, де обробка винятків особливо корисна: обробка помилок під час виконання мережевих запитів та під час читання файлів.

Мережеві запити

У наведеному нижче прикладі ми робимо запит до Google. Ми обробляємо можливі винятки, що можуть виникнути, які визначені в об’єкті `requests.exceptions`:

import requests

try:
    response = requests.get("https://google.com")

    # Перевіряємо, чи знаходиться код відповіді в діапазоні 200-299 (успішна відповідь)
    if 200 <= response.status_code < 300:
        print("Запит виконано успішно!")
    else:
        print(f"Запит не виконано, код стану: {response.status_code}")
except requests.exceptions.RequestException as e:
    print(f"Сталася помилка RequestException: {e}")
except requests.exceptions.ConnectionError as e:
    print(f"Сталася помилка ConnectionError: {e}")
except requests.exceptions.Timeout as e:
    print(f"Сталася помилка Timeout: {e}")
except requests.exceptions.TooManyRedirects as e:
    print(f"Сталася помилка TooManyRedirects: {e}")
except requests.exceptions.HTTPError as e:
    print(f"Сталася помилка HTTPError: {e}")
except Exception as e:
    print(f"Сталася неочікувана помилка: {e}")

Читання даних з файлу

У цьому прикладі ми читаємо дані з файлу `hello.txt`. Ми також обробляємо типові винятки, такі як `FileNotFoundError` та `IOError`:

try:
    with open(file_path, 'r') as file:
        data = file.read()
        print("Вміст файлу:")
        print(data)
except FileNotFoundError as e:
    print(f"Сталася помилка FileNotFoundError: {e}")
except IOError as e:
    print(f"Сталася помилка IOError: {e}")
except Exception as e:
    print(f"Сталася неочікувана помилка: {e}")

Висновок

У цій статті ми вивчили, що таке винятки та чому вони виникають. Ми також з’ясували, що їх потрібно обробляти для підвищення надійності коду та уникнення аварій. Нарешті, ми розглянули, як обробляти винятки, а також як їх ініціювати.

Далі ви можете ознайомитися з поширеними типами помилок у Python та способами їх вирішення.