## ++Тема 7++<br>Ошибки и исключения. Обработка исключений
(c) Яценко Р.Н., 2019-2022
[Учебный центр компьютерных технологий "Кит"](http://kit.kh.ua/)
<img src="https://i.imgur.com/Kh901c1.png" style="width: 150px; position: fixed; top: 10px; right: 10px; border: 0; box-shadow: none; z-index: -1000;">
---
## 1. Ошибки и исключения
----
### Синтаксические ошибки
- **Синтаксические ошибки** нарушают синтаксис и пунктуацию языка. Интерпретатор Python, встретив ошибочное выражение, не знает как его интерпретировать.
- Останавливается выполнение программы и выводится соответствующее сообщение с указанием на место ошибки:
```
>>> 1a = 10
File "<stdin>", line 1
1a = 10
^
SyntaxError: invalid syntax
```
----
### Исключение SyntaxError
- В терминологии языка Python возникло исключение, принадлежащее классу `SyntaxError`
- Согласно документации Python *синтаксические ошибки* относят к ошибкам, а все остальные (*семантические ошибки*) – к исключениям
----
### Исключение NameError
Если вы попытаетесь обратиться к переменной, которой не было присвоено значение, что в случае Python означает, что переменная вообще не была объявлена, она не существует, то возникнет исключение `NameError`:
```
>>> a = 0
>>> print(a + b)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'b' is not defined
```
----
### Исключение ValueError
В примере строку `"Hi"` нельзя преобразовать к целому числу. Возникает исключение `ValueError`, потому что функция `int()` не может преобразовать такое значение:
```
>>> int("Hi")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: invalid literal for int() with base 10: 'Hi'
```
----
### Исключение TypeError
Число `8` и строка `"3"` принадлежат разным типам, операция сложения между которыми не поддерживается. При попытке их сложить возникает исключение `TypeError`:
```
>>> 8 + "3"
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'int' and 'str'
```
----
### Исключение ZeroDivisionError
Деление на ноль вызывает исключение `ZeroDivisionError`:
```
>>> 1/0
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ZeroDivisionError: division by zero
```
----
### Другие типы исключений
Тип исключения | Описание
-|-----
`IOError` | Генерируется, если невозможно выполнить операцию ввода/вывода
`IndexError` | Генерируется, если в последовательности не найден элемент с указанным индексом
`КeyError` | Генерируется, если в словаре не найден указанный ключ
---
## 2. Обработка исключений
----
### Перехват исключений
- Нередко действия пользователя приводят к тому, что в программе возникает исключение. Например, программа ожидает ввод числа, но человек ввел букву. Попытка преобразовать ее к числу приведет к возбуждению исключения `ValueError`
- На этот случай в Python существует специальный оператор, позволяющий перехватывать возникающие исключения и обрабатывать их
----
### Оператор try-except
- В Python перехват исключений выполняет оператор `try-except`. "Try" переводится как "попытаться", "except" -- как исключение
- Словами описать его работу можно так: "Попытаться сделать то-то и то-то, если при этом возникло исключение, то сделать вот это и это":
``` python
try:
# блок инструкций, где может возникнуть исключение
except:
# блок обработки исключения
```
----
### Пример
``` python=
n = input("Введите целое число: ")
try:
n = int(n)
print("Удачно")
except:
print("Что-то пошло не так")
```
----
### Ветка except
**Если в теле try исключения не возникает, то тело ветки except не выполняется**
- Вот пример вывода программы, когда пользователь вводит целое число:
```
Введите целое число: 100
Удачно
```
- А здесь – когда вводит не то, что ожидалось:
```
Введите целое число: AA
Что-то пошло не так
```
----
### Перехват определенных исключений
В теле `try` могут возникать разные исключения, и у каждого из них должен быть свой обработчик. Поэтому более правильным является указание типа исключения после ключевого слова `except`:
``` python=
try:
n = input('Введите целое число: ')
n = int(n)
print("Все нормально. Вы ввели число", n)
except ValueError:
print("Вы ввели не целое число")
```
----
### Множественный перехват исключений
Если в теле `try` возникнет еще какое-нибудь исключение, то оно не будет обработано. Для него надо написать отдельную ветку `except`:
``` python=
try:
a = float(input("Введите делимое: "))
b = float(input("Введите делитель: "))
c = a / b
print("Частное: %.2f" % c)
except ValueError:
print("Нельзя вводить строки")
except ZeroDivisionError:
print("Нельзя делить на ноль")
```
----
### Группировка исключений
Несколько исключений можно сгруппировать в одну ветку и обработать совместно:
``` python=
try:
a = float(input("Введите делимое: "))
b = float(input("Введите делитель: "))
c = a / b
print("Частное: %.2f" % c)
except ValueError, TypeError:
print("Нельзя вводить строки")
except ZeroDivisionError:
print("Нельзя делить на ноль")
```
----
### Ветки else и finally
- Блок **`else` сработает, если исключений в `try` не было**, т. е. не было переходов на блоки `except`
- Блок **`finally` выполняется всегда**, независимо от того, выполнялись ли блоки `except` или нет
``` python=
try:
n = input('Введите целое число: ')
n = int(n)
except ValueError:
print("Вы что-то попутали с вводом")
else: # выполняется, когда в блоке try не возникло исключения
print("Все нормально. Вы ввели число", n)
finally: # выполняется в любом случае
print("Конец программы")
```
----
### Примеры выполнения
```
Введите целое число: 4.3
Вы что-то попутали с вводом
Конец программы
Введите целое число: 4
Все нормально. Вы ввели число 4
Конец программы
```
---
## 3. Вложенная обработка
----
### Обработчики для обработчиков
Исключение может возникнуть в блоке `except`, `else` или `finally`, и тогда им нужен собственный обработчик. Модифицируем немного предыдущую программу и специально сгенерируем исключение в теле `except`:
``` python=
try:
n = input('Введите целое число: ')
n = int(n)
except ValueError:
print("Вы что-то попутали с вводом")
3 / 0
except ZeroDivisionError:
print("Деление на ноль")
else:
print("Все нормально. Вы ввели число", n)
finally:
print("Конец программы")
```
----
### Выполнение
```
Введите целое число: а
Вы что-то попутали с вводом
Конец программы
Traceback (most recent call last):
File "test.py", line 15, in <module>
n = int(n)
ValueError: invalid literal for int() with base 10: 'а'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "test.py", line 18, in <module>
3 / 0
ZeroDivisionError: division by zero
```
Мало того, что не было обработано деление на ноль, само исключение `ValueError` посчиталось необработанным
----
### Решение проблемы
``` python=4
except ValueError:
print("Вы что-то попутали с вводом")
try:
3 / 0
except ZeroDivisionError:
print("Деление на ноль")
```
---
## 4. Полный синтаксис try
----
### try-except-else-finally
``` python=
try:
# Здесь располагается код, который может вызвать исключение
[raise Exception("message")]
# Инструкция raise возбуждает исключение
# Exception, это один из стандартных типов исключения, может
# использоваться любой другой, в том числе пользовательский
except (Тип исключения1, Тип исключения2, ...) [as Переменная]:
# Код в блоке выполняется, если тип исключения совпадает
# с одним из типов (Тип исключения1, Тип исключения2, ...)
# или является наследником одного из этих типов.
# Полученное исключение доступно в необязательной Переменной.
```
----
``` python=12
[except (Тип исключения3, Тип исключения4, ...):]
# Количество блоков except не ограничено
[raise]
# Сгенерировать исключение "поверх" полученного;
# без параметров - повторно сгенерировать полученное
[except:]
# Будет выполнено при любом исключении,
# не обработанном типизированными блоками except
[else:]
# Выполняется код блока, если не было перехвачено исключений.
[finally:]
# Будет исполнено в любом случае, после соответствующего
# блока except или else
```
----
### Пример со списком
``` python=
from random import randint, seed
seed()
L = []
for j in range(20):
L.append(randint(10, 99))
print(L[j], end=' ')
print()
while True:
N = int(input('Введите значение элемента '
'для удаления или 0 для выхода\nN = '))
if not N:
print('Вы вышли из программы')
break
```
----
``` python=16
try:
x = L.index(N)
except ValueError:
print('Такого элемента в массиве не существует!')
else:
L.remove(N)
print('Элемент в позиции', x, 'успешно удален!')
finally:
for it in L:
print(it, end=' ')
print()
```
----
```
50 58 13 41 53 65 27 29 73 52 31 13 64 18 97 42 95 24 37 60
Введите значение элемента для удаления или 0 для выхода
N = 43
Такого элемента в массиве не существует!
50 58 13 41 53 65 27 29 73 52 31 13 64 18 97 42 95 24 37 60
Введите значение элемента для удаления или 0 для выхода
N = 65
Элемент в позиции 5 успешно удален!
50 58 13 41 53 27 29 73 52 31 13 64 18 97 42 95 24 37 60
Введите значение элемента для удаления или 0 для выхода
N = 0
Вы вышли из программы
```
---
## 5. Оператор assert
<!--
https://pythonist.ru/assert-v-python/
-->
----
### Назначение
- Оператор `assert` -- это оператор Python, используемый для отладки кода
- Работает как логическое выражение, проверяя, является ли заданное условие истинным или ложным:
- Если истинно, то ничего не происходит и выполняется следующая строка кода
- Если ложно, оператор assert останавливает выполнение программы и выдает ошибку `AssertionError`
----
### Синтаксис
- Синтаксис использования оператора `assert` следующий:
```python
assert <condition>
```
- Можно добавить дополнительное сообщение, которое будет выводиться, если условие ложно:
```python
assert <condition>, <message>
```
----
### Пример
```python=
num1 = 10
num2 = int(input())
assert num2 != 0, "Делитель равен нулю"
print("Результат:", num1/num2)
```
```
0
Traceback (most recent call last):
File "main.py", line 3, in <module>
AssertionError: Делитель равен нулю
2
Результат: 5.0
```
---
## Домашнее задание
Набрать и запустить на выполнение все примеры программ из лекции

(c) Яценко Р.Н., [УЦКТ "Кит"](http://kit.kh.ua/), 2019-2022
{"metaMigratedAt":"2023-06-16T22:51:26.219Z","metaMigratedFrom":"YAML","title":"Тема 7. Ошибки и исключения. Обработка исключений","breaks":false,"slideOptions":"{\"allottedMinutes\":80,\"transition\":\"slide\",\"theme\":\"beige\",\"slideNumber\":\"c\",\"spotlight\":{\"enabled\":true}}","contributors":"[{\"id\":\"93a8c43f-1b5b-4461-9101-89b183ccbc1c\",\"add\":11243,\"del\":351}]"}