|
|
Програмування мовою Python: основи та практика Електронний посібник |
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
ТЕМА 4. ВИНЯТКИ ТА ЇХ
ОБРОБКА |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
В контексті
Python виняток
є типом даних, що містить інформацію про помилку. Також вживається термін «виняткова
ситуація», який означає випадок, коли виникає виняток. Часто ці терміни
використовують як синоніми.
Syntax errors. Це
вид помилок, з якими ви зіткнетесь першочергово, проте їх дуже легко
виправити. Syntax error вказує на порушення «граматики» Python. Python робить все
можливе, аби вказати на рядок і символ, де було виявлено помилку.
Складність полягає в тому, що іноді він неправильно
визначає місце помилки, і вона є десь
раніше в програмі. Тому рядок і символ, які Python вказує у syntax error, можуть бути
лише початком вашого пошуку. Logic errors. Це помилка, спричинена неправильним
порядком команд чи зв'язком між ними. Наведімо
приклад: «Випийте води, покладіть пляшку в рюкзак, дійдіть до бібліотеки,
а потім закрийте пляшку». Semantic errors. Це
повідомлення означає, що помилка міститься саме в роботі програми.
Тобто, програма написана абсолютно правильно, але вона видає не те, що ви від
неї очікували. Це може бути схоже на ситуацію, коли ви описуєте другу дорогу
до ресторану
і говорите: «Як доїдеш до перехрестя із заправкою, поверни ліворуч і рухайся ще
кілометр, рестораном буде червона будівля зліва від тебе». Ваш друг дуже запізнюється
і дзвонить вам, аби сказати, що він знаходиться на фермі, де замість ресторану
він бачить лише сарай. Ви запитуєте: «На заправці ти повернув ліворуч чи праворуч?»,
а він відповідає: «Я чітко слідував твоїм вказівкам, у мене вони записані, там
сказано повернути ліворуч і проїхати кілометр до заправки». Все, що ви можете йому
відповісти, це лише: «Мені дуже шкода, хоч мої поради і були правильно сформульовані
синтаксично, та, на жаль, містили непомітну семантичну помилку».
Коли Python видає
помилку чи результат,
який відрізняється від того, що ви очікували, починається полювання на
причину помилки.
Після цього можна розпочати все заново. Програмісти-початківці іноді
зациклюються на чомусь одному і забувають про інші способи. Щоб знайти
складний баг, потрібно все ретельно
перевіряти, переробляти, перемірковувати, а іноді навіть повернутися назад. Якщо
ви застрягли на одному з цих етапів, спробуйте інші. Кожен з них має свій
власний алгоритм невдач. Наприклад, перевірка коду може допомогти, якщо проблема полягає в
друкарській помилці, але навряд буде ефективною, якщо йдеться про помилку в
змісті. Якщо ви не розумієте, що робить ваша програма, ви можете переглянути її
хоч 100 разів, а так і не побачите помилку, адже вона у вас в голові. Переробити та внести зміни
особливо допомагає, якщо ви проведете невеличке просте випробування вашої
програми. Однак, якщо робити це бездумно, не перечитавши код, можна потрапити
в ситуацію, яка зветься «блукання в нетрях програми», тобто процес внесення
випадкових змін доти, доки програма не працюватиме належним чином. Зрозуміло,
що таке блукання може зайняти багато часу. Вам потрібен час, щоб подумати.
Необхідно мати принаймні одну гіпотезу, в чому полягає проблема. Якщо їх
дві чи більше, спробуйте зрозуміти, як можна виключити одну з них. Також може
допомогти відпочинок. Так само, як і розмова. Якщо ви поясните проблему
комусь іншому (або навіть собі), то іноді знайдете відповідь ще до того, як
закінчите ставити питання. Але навіть найкращі методи налагодження не спрацюють, якщо помилок
занадто багато, або якщо код, який ви намагаєтеся виправити, занадто великий
і складний. Іноді найкращим варіантом є повернення назад, спрощення програми,
доки ви не повернетеся до моменту, коли все працює. Програмісти-початківці часто не хочуть повертатися назад, адже їм не
хочеться видаляти рядок коду (навіть якщо він неправильний). Щоб стало легше,
скопіюйте свою програму в інший файл, перш ніж починати її видаляти. Отже, ви
зможете поступово додавати частини коду назад до програми. Розгляньмо як приклад, виняток
ділення на нуль. Якщо спробувати виконати операцію, 1/0 то виникне помилка,
оскільки на 0 ділити не можна. Інтерпретатор відреагує на цю помилку
генерацією винятку (припиненням подальшого виконання програми) та виведе
відповідне повідомлення.
Операція застосована до об’єкта невідповідного типу:
Функція отримує аргумент
правильного типу, але некоректного значення:
Синтаксична помилка:
У цих прикладах генеруються винятки: TypeError, ValueError, SyntaxError.
Обробка винятків може полягати у забезпеченні виконання
певного коду або у виправленні стану програми, що викликала виняток. Особливо
це важливо у програмах, які опрацьовують математичні об’єкти, де може бути
проблема області визначення, розривів тощо, що призводить до помилок у
обчисленнях з рухомою точкою. Якісна програма маю обробити ці помилки,
присвоївши відповідній змінній або повідомивши користувача про виникнення
помилки. Якщо передбачити місця та умови виникнення винятків,
можна попередньо налаштувати їх обробку. Для цього використовується конструкція try-except, яка
має кілька форм. У цій конструкції можуть бути використані різні оператори: try, except, else,
finally, raise. Їх використання має свої відповідні
особливості.
Незважаючи на те, що
у цьому варіанті конструкції try – except вказано лише одну назву винятку, фактично будуть оброблені як сам
вказаний виняток, так і всі його нащадки. Наприклад,
у разі перехоплення винятку ArithmeticError
також будуть оброблені винятки FloatingPointError, OverflowError, ZeroDivisionError. Якщо потрібно обробити кілька
винятків, які не є у ієрархічних зв’язках, можна вказати їх назви в
розділених комами дужках у блоці except. Наприклад:
Також можна використовувати ключове слово except без конкретизації
типів винятків. Цей вид
обробника перехоплює всі винятки, включаючи системні, як-от переривання з
клавіатури або системний вихід. Однак такий спосіб майже не використовується
через широкий спектр перехоплюваних винятків. Якщо потрібно обробити
всі несистемні винятки, можна скористатися except
Exception. Крім того, у разі, коли потрібно
різним чином обробляти різні винятки в межах певного оператора або набору операторів, у конструкції try – except можна розмістити кілька блоків except
для відповідних винятків.
У разі виникнення винятку будуть переглянуті блоки except почергово,
зверху донизу, для знаходження відповідного обробника (тільки перший придатний блок except буде виконаний).
Але й на цьому
етапі вказана конструкція try – except не є
повною. Конструкція try – except може мати ще два блоки: finally та else. Код блоку finally виконується
в будь-якому випадку, незалежно від того, чи виник виняток
в блоці try, чи ні. Код блоку else виконується
в тому випадку, якщо винятку в блоці try не було. Блок else
досить добре описує
частину дерева розв’язку: «Якщо цього виконати не можна, то (інакше) виконати
це». Якщо блок else є, то він має йти
після всіх блоків except,
але до блоку finally.
Для прикладу напишемо програму, в
якій для введеного числа X буде
знаходитися частка 1/X. Без
опрацювання винятків ця програма матиме такий вигляд:
Тобто у разі виникнення винятку буде
виведене відповідне повідомлення про помилку. Іноді під час обробки винятків може
бути досить просто вивести системний опис самого винятку. У таких випадках
може бути зручно просто обробити
виняток Exception, повертаючи
опис саме того винятку, який став причиною виникнення помилки та є нащадком Exception.
Надалі в середині відповідного блоку except можна буде звернутися до змінної
і отримати дані про виняток. Наприклад, нашу
попередню задачу перепишемо:
Якщо користувач введе не
ціле число (наприклад, 33.4), то отримає повідомлення:
Якщо користувач введе 0, то отримає повідомлення:
Оператор raise дає змогу програмісту згенерувати
вказаний виняток. В єдиному аргументі
raise вказується виняток, який буде викликано, наприклад:
Ø Механізм
обробки виняткових ситуацій базується
на використанні конструкції
try-except. Якщо під час виконання
програмного коду, поміченого
ключовим словом try, виникає помилка, її може
бути перехоплено й оброблено в одному з блоків, позначених інструкцією except. Для кожного except-блоку після ключового слова except можна вказати
тип помилки (винятку), яка оброблюється цим
блоком
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||