====Исключения в python. Конструкция try - except для обработки исключений====
Исключения (exceptions) - ещё один тип данных в python. Исключения необходимы для того, чтобы сообщать программисту об ошибках.
Самый простейший пример исключения - деление на ноль:
>>>
>>> 100 / 0
Traceback (most recent call last):
File "", line 1, in
100 / 0
ZeroDivisionError: division by zero
Разберём это сообщение подробнее: интерпретатор нам сообщает о том, что он поймал исключение и напечатал информацию **(Traceback (most recent call last)).**
Далее имя файла **(File "")**. Имя пустое, потому что мы находимся в интерактивном режиме, строка в файле (line 1);
Выражение, в котором произошла ошибка **(100 / 0).**
Название исключения **(ZeroDivisionError)** и краткое описание исключения **(division by zero).**
Разумеется, возможны и другие исключения:
>>>
>>> 2 + '1'
Traceback (most recent call last):
File "", line 1, in
2 + '1'
TypeError: unsupported operand type(s) for +: 'int' and 'str'
>>> int('qwerty')
Traceback (most recent call last):
File "", line 1, in
int('qwerty')
ValueError: invalid literal for int() with base 10: 'qwerty'
В этих двух примерах генерируются исключения TypeError и ValueError соответственно. Подсказки дают нам полную информацию о том, где порождено исключение, и с чем оно связано.
Рассмотрим иерархию встроенных в python исключений, хотя иногда вам могут встретиться и другие, так как программисты могут создавать собственные исключения. Данный список актуален для python 3.3, в более ранних версиях есть незначительные изменения.
* **BaseException** - базовое исключение, от которого берут начало все остальные.
* **SystemExit** - исключение, порождаемое функцией sys.exit при выходе из программы.
* **KeyboardInterrupt** - порождается при прерывании программы пользователем (обычно сочетанием клавиш Ctrl+C).
* **GeneratorExit** - порождается при вызове метода close объекта generator.
* **Exception** - а вот тут уже заканчиваются полностью системные исключения (которые лучше не трогать) и начинаются обыкновенные, с которыми можно работать.
* **StopIteration** - порождается встроенной функцией next, если в итераторе больше нет элементов.
* **ArithmeticError** - арифметическая ошибка.
* **FloatingPointError** - порождается при неудачном выполнении операции с плавающей запятой. На практике встречается нечасто.
* **OverflowError** - возникает, когда результат арифметической операции слишком велик для представления. Не появляется при обычной работе с целыми числами (так как python поддерживает длинные числа), но может возникать в некоторых других случаях.
* **ZeroDivisionError** - деление на ноль.
* **AssertionError** - выражение в функции assert ложно.
* **AttributeError** - объект не имеет данного атрибута (значения или метода).
* **BufferError** - операция, связанная с буфером, не может быть выполнена.
* **EOFError** - функция наткнулась на конец файла и не смогла прочитать то, что хотела.
* **ImportError** - не удалось импортирование модуля или его атрибута.
* **LookupError** - некорректный индекс или ключ.
* **IndexError** - индекс не входит в диапазон элементов.
* **KeyError** - несуществующий ключ (в словаре, множестве или другом объекте).
* **MemoryError** - недостаточно памяти.
* **NameError** - не найдено переменной с таким именем.
* **UnboundLocalError** - сделана ссылка на локальную переменную в функции, но переменная не определена ранее.
* **OSError** - ошибка, связанная с системой.
* **BlockingIOError**
* **ChildProcessError** - неудача при операции с дочерним процессом.
* **ConnectionError** - базовый класс для исключений, связанных с подключениями.
* **BrokenPipeError**
* **ConnectionAbortedError**
* **ConnectionRefusedError**
* **ConnectionResetError**
* **FileExistsError** - попытка создания файла или директории, которая уже существует.
* **FileNotFoundError** - файл или директория не существует.
* **InterruptedError** - системный вызов прерван входящим сигналом.
* **IsADirectoryError** - ожидался файл, но это директория.
* **NotADirectoryError** - ожидалась директория, но это файл.
* **PermissionError** - не хватает прав доступа.
* **ProcessLookupError** - указанного процесса не существует.
* **TimeoutError** - закончилось время ожидания.
* **ReferenceError** - попытка доступа к атрибуту со слабой ссылкой.
* **RuntimeError** - возникает, когда исключение не попадает ни под одну из других категорий.
* **NotImplementedError** - возникает, когда абстрактные методы класса требуют переопределения в дочерних классах.
* **SyntaxError** - синтаксическая ошибка.
* **IndentationError** - неправильные отступы.
* **TabError** - смешивание в отступах табуляции и пробелов.
* **SystemError** - внутренняя ошибка.
* **TypeError** - операция применена к объекту несоответствующего типа.
* **ValueError** - функция получает аргумент правильного типа, но некорректного значения.
* **UnicodeError** - ошибка, связанная с кодированием / раскодированием unicode в строках.
* **UnicodeEncodeError** - исключение, связанное с кодированием unicode.
* **UnicodeDecodeError** - исключение, связанное с декодированием unicode.
* **UnicodeTranslateError** - исключение, связанное с переводом unicode.
* **Warning** - предупреждение.
Теперь, зная, когда и при каких обстоятельствах могут возникнуть исключения, мы можем их обрабатывать. Для обработки исключений используется конструкция **try - except**.
Первый пример применения этой конструкции:
>>>
>>> try:
... k = 1 / 0
... except ZeroDivisionError:
... k = 0
...
>>> print(k)
0
В блоке try мы выполняем инструкцию, которая может породить исключение, а в блоке except мы перехватываем их. При этом перехватываются как само исключение, так и его потомки. Например, перехватывая ArithmeticError, мы также перехватываем FloatingPointError, OverflowError и ZeroDivisionError.
>>>
>>> try:
... k = 1 / 0
... except ArithmeticError:
... k = 0
...
>>> print(k)
0
Также возможна инструкция except без аргументов, которая перехватывает вообще всё (и прерывание с клавиатуры, и системный выход и т. д.). Поэтому в такой форме инструкция except практически не используется, а используется except Exception. Однако чаще всего перехватывают исключения по одному, для упрощения отладки (вдруг вы ещё другую ошибку сделаете, а except её перехватит).
Ещё две инструкции, относящиеся к нашей проблеме, это **finally** и else. Finally выполняет блок инструкций в любом случае, было ли исключение, или нет (применима, когда нужно непременно что-то сделать, к примеру, закрыть файл). Инструкция else выполняется в том случае, если исключения не было.
>>> f = open('1.txt')
>>> ints = []
>>> try:
... for line in f:
... ints.append(int(line))
... except ValueError:
... print('Это не число. Выходим.')
... except Exception:
... print('Это что ещё такое?')
... else:
... print('Всё хорошо.')
... finally:
... f.close()
... print('Я закрыл файл.')
... # Именно в таком порядке: try, группа except, затем else, и только потом finally.
Это не число. Выходим.
Я закрыл файл.