Винятки#
Винятки трапляються, коли у вашій програмі виникають виняткові (exceptional) ситуації. Наприклад,якщо ви збираєтеся прочитати файл, а файл не існує? Або, якщо ви випадково видалили файл під час роботи програми? Такі ситуації обробляються за допомогою винятків (англ.“exceptions”).
Подібним чином, якби ваша програма мала деякі неприпустимі команди? У цьому випадку Python піднімає (англ.“raises”)руки та повідомляє, що виявив помилку (англ.“error”).
Помилки#
Розглянемо простий виклик функції print
. Що, якщо ми помилково напишемо print
як Print
? Зверніть увагу на використання великих літер (англ.“capitalization”). У цьому випадку Python піднімає синтаксичну помилку.
Приклад англійською:
>>> Print("Hello World")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'Print' is not defined
>>> print("Hello World")
Hello World
Приклад українською (скріншот, зроблений в оболонці Python за допомогою IDLE):
де: name ‘Print’ is not defined.Did you mean:‘print’? - ім’я «Print» не визначено. Ви мали на увазі :‘print’?
Зверніть увагу, що була підіймана помилкаNameError
,а також друкується місце, де було виявлено помилку. Так у цьому випадку діє обробник помилок (англ.“error handler”).
Винятки#
Ми спробуємо (англ.“try”) прочитати щось від користувача. Введіть перший рядок нижче та натисніть клавішу Enter
. Коли ваш комп’ютер запропонує вам ввести дані, натомість натисніть [ctrl-d]
на Mac або [ctrl-z]
на Windows і подивіться, що станеться. (Якщо ви користуєтеся Windows і жоден із варіантів не працює, ви можете спробувати [ctrl-c]
у командному рядку, тобто створити KeyboardInterrupt error).
Приклад англійською, автор використувує [ctrl-d]
чи [ctrl-z]
:
>>> s = input('Enter something --> ')
Enter something --> Traceback (most recent call last):
File "<stdin>", line 1, in <module>
EOFError
Python підіймає помилку під назвою end-of-file (EOFError
)(для користувачів,які використувують [ctrl-d]
чи [ctrl-z]
), яка в основному означає, що він знайшов символ кінця файлу.
Приклад українською ( скріншот [ctrl-c]
, зроблений в оболонці Python за допомогою IDLE):
Python підіймає помилку під назвою KeyboardInterrupt Error
(для користувачів,які використувують [ctrl-c]
).
І в англійському, і в українському варіанті сталася помилка.
Обробка винятків#
англійська: Handling Exceptions
Ми можемо обробляти винятки за допомогою оператора try..except
. По суті, ми розміщуємо наші звичайні команди в блоці try, а всі наші обробники винятків помилок – у блоці except.
код python exceptions_handle_ukr.py
try:
text = input('Введіть щось --> ')
except EOFError:
print('Чому ви прислалі мені символ кінця файлу?')
except KeyboardInterrupt:
print('Ви скасували операцію.')
else:
print('Ви увійшли{}'.format(text))
Висновок:
$ python exceptions_handle_ukr.py
Введіть щось --> # натисніть ctrl + d
Чому ви прислалі мені сигнал кінец файлу?
$ python exceptions_handle_ukr.py
Введіть щось --> # натисніть ctrl + c
Ви скасували операцію.
$ python exceptions_handle_ukr.py
Введіть щось --> Без винятків
Ви увійшли Без винятків
Підказка: якщо CTRL+c закриває вікно терміналу замість того, щоб створити очікуване повідомлення про помилку, спробуйте написати цю програму за допомогою IDLE (Меню: File -> New File, потім натисніть Run -> Run module)
Як це працює
Ми розміщуємо всі командии, які можуть спричиняти винятки/помилки у блоці try
, а потім розміщуємо обробники відповідних помилок/винятків у блоці except
. Вираз except
може обробляти як одиночну помилку або виняток, так і список помилок/винятків у дужках. Якщо не надано назви помилок чи винятків, він оброблятимe всі помилки та винятки.
Зауважте, що для кожного виразу try
має бути принаймні одне речення except
. Інакше який сенс мати блок try?
Якщо будь-яка помилка чи виняток не оброблені, тоді викликається обробник Python за замовчуванням, який просто зупиняє виконання програми та друкує повідомлення про помилку. Ми вже бачили це в дії вище.
Також можна додати пункт else
до відповідного блоку try..except
. Пункт else
виконується, якщо не відбувається винятків.
У наступному прикладі ми також побачимо, як отримати об’єкт винятку, щоб ми могли отримати додаткову інформацію.
Виклик винятків#
англійська: Raising Exceptions
Ви можете викликати винятки за допомогою оператора raise
, передавши йому ім’я помилки або винятку, а також об’єкт винятку, який потрібно викинути.
Помилка або виняток, який ви можете викликати, має бути класом, який прямо чи опосередковано є похідним від класу Exception
.
код python exceptions_raise_ukr.py:
class Виняток_короткого_введення(Exception):
'''Визначений користувачем клас винятків.'''
def __init__(self, довжина, як_мінімум):
Exception.__init__(self)
self.довжина = довжина
self.як_мінімум = як_мінімум
try:
текст = input('Введіть щось --> ')
if len(текст) < 3:
raise Виняток_короткого_введення(len(текст), 3)
# Тут може відбуватися звичайна робота
except EOFError:
print('Чому ви прислалі мені символ кінця файлу?')
except Виняток_короткого_введенн as вн:
print(('Виняток_короткого_введення: Довжина_введеного_рядка ' +
'{0} очікувалося_як_мінімум {1}')
.format(вн.довжина, вн.як_мінімум))
else:
print('Винятків не було.')
Висновок:
$ python exceptions_raise_ukr.py
Введіть щось --> a
Виняток_короткого_введення: Довжина_введеного_рядка очікувалося_як_мінімум 3
$ python exceptions_raise_ukr.py
Введіть щось --> abc
Винятків не було.
python code exceptions_raise_en.py:
class ShortInputException(Exception):
'''A user-defined exception class.'''
def __init__(self, length, atleast):
Exception.__init__(self)
self.length = length
self.atleast = atleast
try:
text = input('Enter something --> ')
if len(text) < 3:
raise ShortInputException(len(text), 3)
# Other work can continue as usual here
except EOFError:
print('Why did you do an EOF on me?')
except ShortInputException as ex:
print(('ShortInputException: The input was ' +
'{0} long, expected at least {1}')
.format(ex.length, ex.atleast))
else:
print('No exception was raised.')
output:
$ python exceptions_raise_en.py
Enter something --> a
ShortInputException: The input was 1 long, expected at least 3
$ python exceptions_raise_en.py
Enter something --> abc
No exception was raised.
Як це працює
Тут ми створюємо власний тип винятку. Цей новий тип винятку називається Виняток_короткого_введення
. У ньому є два поля: довжина
, що зберігає довжину введеного тексту, і як_мінімум
, що вказує, яку мінімальну довжину тексту очікувала програма.
У пункті except
ми вказуємо клас помилки, який зберігатиметься як
(англ.as
) змінна вн
, що містить відповідний об’єкт помилки/виключення. Це аналогічно параметрам і аргументам у виклику функції. Всередині цього пункту except
ми використовуємо поля довжину
і як_мінімум
об’єкта винятку, щоб надрукувати відповідне повідомлення для користувача.
Try … Finally#
Припустимо, ви читаєте файл у своїй програмі. Як переконатися, що об’єкт файлу був коректно закритий і що не виникло жодного винятку? Це можна зробити за допомогою блоку finally
.
код python exceptions_finally_ukr.py:
import sys
import time
f = None
try:
f = open("вірш.txt")
# наш звичайний спосіб читати файли
while True:
лінія = f.readline()
if len(лінія) == 0:
break
print(лінія, end='')
sys.stdout.flush()
print("Натисніть ctrl+c зараз")
# Щоб переконатися, що він працює деякий час
time.sleep(2)
except IOError:
print("Не вдалося знайти файл вірш.txt")
except Клавіатура_переривання:
print("!! Ви скасували читання з файлу.")
finally:
if f:
f.close()
print("(Очищення: файл закрито)")
Висновок:
$ python exceptions_finally_ukr.py
Програмування – це весело.
Натисніть ctrl+c зараз
^C!! Ви скасували читання з файлу.
(Очищення: файл закрито)
python code exceptions_finally_en.py:
import sys
import time
f = None
try:
f = open("poem.txt")
# Our usual file-reading idiom
while True:
line = f.readline()
if len(line) == 0:
break
print(line, end='')
sys.stdout.flush()
print("Press ctrl+c now")
# To make sure it runs for a while
time.sleep(2)
except IOError:
print("Could not find file poem.txt")
except KeyboardInterrupt:
print("!! You cancelled the reading from the file.")
finally:
if f:
f.close()
print("(Cleaning up: Closed the file)")
output:
$ python exceptions_finally.py
Programming is fun
Press ctrl+c now
^C!! You cancelled the reading from the file.
(Cleaning up: Closed the file)
Як це працює
Ми виконуємо звичайне читання файлів, але ми довільно ввели сплячий режим протягом 2 секунд після друку кожного рядка за допомогою функції time.sleep
, щоб програма працювала повільно (Python дуже швидкий за своєю природою). Коли програма все ще працює, натисніть ctrl + c
, щоб перервати/скасувати програму.
Зверніть увагу, що виникає виняток Клавіатура_переривання
і програма завершує роботу. Однак перед завершенням роботи програми виконується пункт finally, і файловий об’єкт завжди закривається.
Зауважте, що змінна, якій присвоєно значення 0 або None
, або змінна, яка є порожньою послідовністю чи колекцією, вважається False
у Python. Ось чому ми можемо використовувати if f:
у коді вище.
Також зауважте, що ми використовуємо sys.stdout.flush()
після print
, щоб він негайно друкувався на екрані.
Оператор with#
англійська: The with statement
Типовою схемою є запит деякого ресурсу в блоці try
і подальше звільнення цього ресурсу в блоці finally
. Отже, є також оператор with
, який дозволяє це зробити більш “чисто”:
Зберегти якexceptions_using_with.py
:
код python exceptions_using_with_ukr.py:
with open("вірш.txt") as f:
for лінія in f:
print(лінія, end='')
Як це працює
Результат має бути таким самим, як у попередньому прикладі. Різниця тут полягає в тому, що ми використовуємо функцію open
з оператором with
- цим ми залишаємо автоматичне закриття файлу під відповідальність with open
.
Те, що відбувається за кулісами, полягає в тому, що існує такий собі протокол, який використовується оператором with. Він зчитує об’єкт, який повертається оператором open
, назвемо його в даному випадку “thefile”.
Перед запуском блоку коду, що міститься в ньому, оператор with
завжди викликає функцію із файлуthefile.__enter__
,а також завжди викликає thefile.__exit__
після завершення цього блоку кода.
Таким чином, код, який ми б написали в блоці finally
, повинен автоматично оброблятися методом __exit__
. Це те, що допомагає нам уникнути повторного використання явних операторів try..finally
.
Додаткове обговорення цієї теми виходить за рамки цієї книги, тому, будь ласка, зверніться до PEP 343 для вичерпного пояснення.
Що робить оператор with (від перекладача):#
Кожен файловий об’єкт має дві функції: enter та exit. Оператор with
спочатку викликає функцію enter об’єкта файлу, потім виконує всі рядки коду всередині блоку with
, а після завершення викликає функцію exit цього ж об’єкта.
Без блоку with вам потрібно написати код так:
код python poem_ukr.py:
f = open("вірш.txt")
# ще кілька команд Python
f.close()
# інший код
python code poem_en.py
f = open("poem.txt")
# some more python commands
f.close()
# other code
Використовуючи блок with, ви можете писати елегантніше і не турбуватись про закриття файлу:
код python poem2_ukr.py:
with open("вірш.txt") as f:
print("файл зараз відкрит")
# ще кілька команд Python
# тепер автоматично закривається!
print("файл зараз закрит")
# інший код
python code poem2_en.py
with open("poem.txt") as f:
print("file is now open")
# some more python commands
# now automatically closed!
print("file is now closed")
# other code
Резюме#
Ми обговорили використання операторів try..except
і try..finally
. Ми побачили, як створювати власні типи винятків, а також як викликати винятки.
Далі ми вивчимо стандартну бібліотеку Python.