Як перехопити кілька винятків у Python: простий посібник

Обробка винятків у Python є важливим аспектом створення стабільних та надійних програм. Вона дозволяє уникнути непередбачуваних збоїв та забезпечує кращий користувацький досвід. У цьому матеріалі ми розглянемо, як ефективно обробляти кілька винятків в одному блоці `try/except` у Python.

Що таке винятки в Python?

У Python винятки є засобом сповіщення про виникнення помилок під час виконання програми. Коли певна частина коду стикається з критичною ситуацією, яку вона не може самостійно вирішити, вона “викидає” виняток. Інша частина програми, яка підготовлена до обробки такого роду ситуацій, може “перехопити” цей виняток та відреагувати належним чином.

Якщо виняток не обробляється, це призводить до аварійного завершення програми. Тому, обробка винятків є ключовою для створення стійких і надійних застосунків. Якщо ви новачок у цій темі, радимо ознайомитись зі статтею “Вступ до Python Try/Except”, де розглядаються базові принципи створення та обробки винятків.

Чому важливо обробляти кілька винятків?

  • Це дозволяє зменшити дублювання коду, об’єднуючи обробку кількох винятків в одному блоці. Таким чином, код стає більш читабельним, його легше редагувати та підтримувати.
  • Такий підхід сприяє написанню більш ефективного коду, оскільки перевірка типу помилки потрібна лише один раз, а не для кожного винятку окремо.

Обробка кількох винятків

Обробка кількох винятків означає перехоплення різних типів винятків за допомогою одного блоку `except`. У Python можна обробляти винятки як в окремих блоках, так і групувати їх, якщо вони вимагають схожої обробки. У цьому розділі ми розглянемо різні підходи до обробки кількох винятків на конкретному прикладі.

#1. Перехоплення різних винятків в окремих блоках

Уявімо собі програму, яка отримує два числа від користувача і виконує їх ділення. Ми передбачаємо, що можуть виникнути помилки різних типів, якщо користувач введе недійсні дані. Зокрема, нас цікавить обробка помилок `ValueError` (якщо введено не число) та `ZeroDivisionError` (якщо дільник дорівнює нулю). У кожному випадку ми хочемо вивести повідомлення про помилку “Введено недійсне значення”.

Ось приклад коду, який реалізує цей підхід:

try:
    dividend = int(input('Введіть перше число: '))
    divisor = int(input('Введіть друге число: '))
    quotient = dividend / divisor
    print(quotient)
except ValueError as e:
    print("Введено недійсне значення")
except ZeroDivisionError as e:
    print("Введено недійсне значення")
except Exception as e:
    print("Щось пішло не так")

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

А якщо ввести 0 як друге число, отримаємо:

Код працює правильно, але зверніть увагу, що обробка помилок `ValueError` та `ZeroDivisionError` є ідентичною. Це означає дублювання коду, що не є ідеальним рішенням. Згідно з принципом DRY (“Don’t Repeat Yourself”) у програмуванні, ми повинні уникати зайвого повторення коду.

Замість окремих блоків `except` ми можемо об’єднати їх в один, який перехоплює кілька винятків одночасно. Це дозволить нам позбутися дублювання коду.

#2. Перехоплення кількох винятків в одному блоці `except`

Для обробки кількох винятків в одному блоці `except` потрібно передати кортеж з типами помилок, які ми хочемо перехопити. Ось приклад, як це виглядає на практиці:

try:
    dividend = int(input('Введіть перше число: '))
    divisor = int(input('Введіть друге число: '))
    quotient = dividend / divisor
    print(quotient)
except (ValueError, ZeroDivisionError) as e:
    print("Введено недійсне значення")
except Exception as e:
    print("Щось пішло не так")

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

#3. Визначення, який виняток було перехоплено

Попередній код виконує один і той же блок коду, незалежно від того, виникла помилка `ValueError` чи `ZeroDivisionError`. Але іноді вам потрібно виконати різний код залежно від типу винятку.

Щоб визначити, який саме виняток було перехоплено, можна скористатися конструкцією `if/else` всередині блоку `except`. Наприклад:

try:
    dividend = int(input('Введіть перше число: '))
    divisor = int(input('Введіть друге число: '))
    quotient = dividend / divisor
    print(quotient)
except (ValueError, ZeroDivisionError) as e:
    print("Введено недійсне значення")

    if isinstance(e, ValueError):
        print('Помилка значення')
    else:
        print('Помилка ділення на нуль')
except Exception as e:
    print("Щось пішло не так")

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

Коли доцільно обробляти кілька винятків?

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

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

Висновок

У цій статті ми розглянули, як об’єднувати кілька блоків `except` в один, перехоплюючи одразу кілька винятків. Це робить код більш читабельним, лаконічним та простим в обслуговуванні. Далі ви можете переглянути статтю про Python-проекти для початківців, які варто спробувати.