Обробка винятків Python

При програмуванні на Python ми можемо зіткнутися з двома типами помилок. Перший тип представляють синтаксичні помилки (syntax error). Вони з'являються в результаті порушення синтаксису мови програмування при написанні вихідного коду. При наявності таких помилок програма не може бути скомпільована. При роботі в будь-якому середовищі розробки, наприклад, в PyCharm, IDE сама може відстежувати синтаксичні помилки і якимось чином їх виділяти.

Другий тип помилок представляють помилки виконання (runtime error). Вони з'являються у вже скомпільованій програмі в процесі її виконання. Подібні помилки ще називаються винятками. Наприклад, у минулих темах ми розглядали перетворення числа в рядок:

string = "5"  
number = int(string)  
print(number)  

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

string = "hello"  
number = int(string)  
print(number)  

При виконанні цього скрипта буде викинуто виняток ValueError, так як рядок "hello" не можна перетворити в число. З одного боку, тут очевидно, сто рядок не представляє число, але ми можемо мати справу з введенням користувача, який також може ввести не зовсім те, що ми очікуємо:

string = input("Введіть число: ")  
number = int(string)  
print(number)  

При виникненні винятку робота програми переривається, і щоб уникнути подібної поведінки і обробляти винятки в Python є конструкція try..except, яка має таке формальне визначення:

try:  
    інструкція  
except [Тип_исключения]:  
    інструкція  

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

Після ключового слова except опціонально можна вказати, яке виняток буде оброблятися (наприклад, ValueError або KeyError). Після слова except на наступному рядку йдуть інструкції блоку except, що виконуються при виникненні винятку.

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

try:  
    number = int(input("Введіть число: "))  
    print("Введене число:", number)  
except:  
    print("Перетворення пройшло невдало")  
print("Завершення програми")

Вводимо рядок:

Введіть число: hello
Перетворення пройшло невдало
Завершення програми

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

Вводимо правильне число:

Введіть число: 22
Введене число: 22
Завершення програми

Тепер все виконується нормально, виняток не виникає, і відповідно блок except не виконується.

У прикладі вище оброблялися відразу всі винятки, які можуть виникнути в коді. Однак ми можемо конкретизувати тип оброблюваного винятку, вказавши його після слова except:

try:  
    number = int(input("Введіть число: "))  
    print("Введене число:", number)  
except ValueError:  
    print("Перетворення пройшло невдало")  
print("Завершення програми")

Якщо ситуація така, що в програмі можуть бути згенеровані різні типи винятків, то ми можемо їх обробити окремо, використовуючи додаткові вираження except:

try:  
    number1 = int(input("Введіть перше число: "))  
    number2 = int(input("Введіть друге число: "))  
    print ("результат поділу:", number1/number2)  
except ValueError:  
    print("Перетворення пройшло невдало")  
except ZeroDivisionError:  
    print ("спроба ділення числа на нуль")  
except Exception:  
    print ("загальне виключення")  
print("Завершення програми") 

Якщо виникне виняток в результаті перетворення рядка в число, то воно буде оброблено блоком except ValueError. Якщо ж друге число дорівнюватиме нулю, тобто буде поділ на нуль, тоді виникне виключення ZeroDivisionError, і воно буде оброблено блоком except ZeroDivisionError.

Тип Exception представляє загальний виняток, під який потрапляють всі виняткові ситуації. Тому в даному випадку будь-який виняток, який не представляє тип ValueError або ZeroDivisionError, буде оброблено в блоці except Exception:.

Блок finally

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

try:  
    number = int(input("Введіть число: "))  
    print("Введене число:", number)  
except ValueError:  
    print("Не вдалося перетворити число")  
finally:  
    print("Блок try завершив виконання")  
print("Завершення програми")  

Як правило, блок finally застосовується для звільнення використовуваних ресурсів, наприклад, для закриття файлів.

Отримання інформації про виключення

З допомогою оператора as ми можемо передати всю інформацію про виключення в змінну, яку потім можна використовувати в блоці except:

try:  
    number = int(input("Введіть число: "))  
    print("Введене число:", number)  
except ValueError as e:  
    print("Відомості про виключення", e)  
print("Завершення програми")

Приклад некоректного введення:

Введіть число: fdsf
Відомості про виключення invalid literal for int() with base 10: 'fdsf'
Завершення програми

Генерація винятків

Іноді виникає необхідність вручну згенерувати той чи інший виняток. Для цього застосовується оператор raise.

try:  
    number1 = int(input("Введіть перше число: "))  
    number2 = int(input("Введіть друге число: "))  
    if number2 == 0:  
        raise Exception ("друге число не повинно дорівнювати 0")  
    print("Результат ділення двох чисел:", number1/number2)  
except ValueError:  
    print("Введені некоректні дані")  
except Exception as e:  
    print(e)  
print("Завершення програми")

При виклику виключення ми можемо йому передати повідомлення, яке потім можна вивести користувачеві:

Введіть перше число: 1
Введіть друге число: 0
Друге число не повинно дорівнювати 0
Завершення програми