Исключения в Python

Справочник

Исключения (Exceptions) Python

Исключения (exceptions) — ещё один тип данных в python. Исключения необходимы для того, чтобы сообщать программисту об ошибках. Самый простой пример исключения — деление на ноль. Если попробовать запустить такую программу

z = 100 / 0

она завершится с ошибкой

Traceback (most recent call last):
  File "", line 1, in 
ZeroDivisionError: division by zero

ZeroDivisionError — это название исключения, а division by zero — его краткое описание. Также Python сообщит номер строки, где это исключение возникло.

Разумеется, возможны и другие исключения. Например, при попытке сложить строку и число

z = 2 + '1'

произойдет исключение TypeError

Traceback (most recent call last):
  File "", line 1, in 
TypeError: unsupported operand type(s) for +: 'int' and 'str'

В этом примере генерируется исключение TypeError. Подсказки дают нам полную информацию о том, где порождено исключение, и с чем оно связано.

Рассмотрим иерархию встроенных в python исключений, хотя иногда вам могут встретиться и другие, так как программисты могут создавать собственные исключения.

  • 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 — Базовый класс для исключений-предупреждений. Данное семейство исключений представляет собой различные категории предупреждений.

    • BYTESWARNING — Предупреждения, связанные с возможными проблемами при работе с байтами. Данная категория предупреждений используется в случаях возможных ошибок при работе с бйтами (bytes и bytearray).
    • DeprecationWarning — Категория предупреждений о функциональности нежелательной к использованию. Эту категорию обычно используют для указания на то, что некая часть функциональности морально устарела (возможно ей на смену пришла более совершенная) и не рекомендуется к использованию.
    • FUTUREWARNING — Категория, описывающая предупреждения об изменениях в будущем. Предупреждения данной категории призваны оповещать о грядущих [семантических] изменениях.
      Пример предупреждения о грядущих изменениях из numpy:
      FutureWarning: comparison to 'None' will result in an elementwise object comparison in the future.
    • IMPORTWARNING — предупреждение о вероятной ошибке при импорте модуля. Предупреждения данной категории могут использоваться, например, в случаях внесения изменений в систему импорта при помощи перехватчиков (хуков).
    • PendingDeprecationWarning — Категория предупреждений о функциональности, которая вскоре должна стать нежелательной к использованию.
    • ResourceWarning — Предупреждения, связанные с возможными проблемами при работе с ресурсами. Примером использования данной категории предупреждений можут служить указание на необходимость закрытия сокета, что необходимо для высвобождения ресурсов.
    • RuntimeWarning — Предупреждение о сомнительном поведении во время исполнения. Категория может быть использована для обозначения сомнительного поведения приложения, например, если код выявил вероятные погрешности в вычислениях.
    • SyntaxWarning — Предупреждение об использовании сомнительных синтаксических конструкций. Категория используется в случаях, когда замечены вероятные синтаксические ошибки.
    • UnicodeWarning — Предупреждения, связанные с возможными проблемами при работе с Юникод.
    • USERWARNING — Класс для пользовательских предупреждений. Может использоваться пользователями в качестве базового класса для создания собственных иерархий предупреждений.

Теперь, зная, когда и при каких обстоятельствах могут возникнуть исключения, мы можем их обрабатывать. Для обработки исключений используется конструкция 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.
Это не число. Выходим.
Я закрыл файл.