Меню

Python baseexception вывод ошибки

Данный урок посвящен исключениям и работе с ними. Основное внимание уделено понятию исключения в языках программирования, обработке исключений в Python, их генерации и созданию пользовательских исключений.

Исключения в языках программирования

Исключениями (exceptions) в языках программирования называют проблемы, возникающие в ходе выполнения программы, которые допускают возможность дальнейшей ее работы в рамках основного алгоритма. Типичным примером исключения является деление на ноль, невозможность считать данные из файла (устройства), отсутствие доступной памяти, доступ к закрытой области памяти и т.п. Для обработки таких ситуаций в языках программирования, как правило, предусматривается специальный механизм, который называется обработка исключений (exception handling).

Исключения разделяют на синхронные и асинхронные. Синхронные исключения могут возникнуть только в определенных местах программы. Например, если у вас есть код, который открывает файл и считывает из него данные, то исключение типа “ошибка чтения данных” может произойти только в указанном куске кода. Асинхронные исключения могут возникнуть в любой момент работы программы, они, как правило, связаны с какими-либо аппаратными проблемами, либо приходом данных. В качестве примера можно привести сигнал отключения питания.

В языках программирования чаще всего предусматривается специальный механизм обработки исключений. Обработка может быть с возвратом, когда после обработки исключения выполнение программы продолжается с того места, где оно возникло. И обработка без возврата, в этом случае, при возникновении исключения, осуществляется переход в специальный, заранее подготовленный, блок кода.

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

В Python выделяют два различных вида ошибок: синтаксические ошибки и исключения.

Синтаксические ошибки в Python

Синтаксические ошибки возникают в случае если программа написана с нарушениями требований Python к синтаксису. Определяются они в процессе парсинга программы. Ниже представлен пример с ошибочным написанием функции print.

>>> for i in range(10):
    prin("hello!")

Traceback (most recent call last):
  File "<pyshell#2>", line 2, in <module>
    prin("hello!")
NameError: name 'prin' is not defined

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

Второй вид ошибок – это исключения. Они возникают в случае если синтаксически программа корректна, но в процессе выполнения возникает ошибка (деление на ноль и т.п.). Более подробно про понятие исключения написано выше, в разделе “исключения в языках программирования”.

Пример исключения ZeroDivisionError, которое возникает при делении на 0.

>>> a = 10
>>> b = 0
>>> c = a / b
Traceback (most recent call last):
  File "<pyshell#5>", line 1, in <module>
    c = a / b
ZeroDivisionError: division by zero

В Python исключения являются определенным типом данных, через который пользователь (программист) получает информацию об ошибке. Если в коде программы исключение не обрабатывается, то приложение останавливается и в консоли печатается подробное описание произошедшей ошибки с указанием места в программе, где она произошла и тип этой ошибки.

Иерархия исключений в Python

Существует довольно большое количество встроенных типов исключений в языке Python, все они составляют определенную иерархию, которая выглядит так, как показано ниже.

BaseException
+– SystemExit
+– KeyboardInterrupt
+– GeneratorExit
+– Exception
     +– StopIteration
     +– StopAsyncIteration
     +– ArithmeticError
     |    +– FloatingPointError
     |    +– OverflowError
     |    +– ZeroDivisionError
     +– AssertionError
     +– AttributeError
     +– BufferError
     +– EOFError
     +– ImportError
          +– ModuleNotFoundError
     +– 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
     |    +– RecursionError
     +– SyntaxError
     |    +– IndentationError
     |         +– TabError
     +– SystemError
     +– TypeError
     +– ValueError
     |    +– UnicodeError
     |         +– UnicodeDecodeError
     |         +– UnicodeEncodeError
     |         +– UnicodeTranslateError
     +– Warning
          +– DeprecationWarning
          +– PendingDeprecationWarning
          +– RuntimeWarning
          +– SyntaxWarning
          +– UserWarning
          +– FutureWarning
          +– ImportWarning
          +– UnicodeWarning
          +– BytesWarning
          +– ResourceWarning

Как видно из приведенной выше схемы, все исключения являются подклассом исключения BaseException. Более подробно об иерархии исключений и их описании можете прочитать здесь.

Обработка исключений в Python

Обработка исключений нужна для того, чтобы приложение не завершалось аварийно каждый раз, когда возникает исключение. Для этого блок кода, в котором возможно появление исключительной ситуации необходимо поместить во внутрь синтаксической конструкции try…except.

print("start")
try:
   val = int(input("input number: "))
   tmp = 10 / val
   print(tmp)
except Exception as e:
   print("Error! " + str(e))
print("stop")

В приведенной выше программе возможных два вида исключений – это ValueError, возникающее в случае, если на запрос программы “введите число”, вы введете строку, и ZeroDivisionError – если вы введете в качестве числа 0.

Вывод программы при вводе нулевого числа будет таким.

start input number: 0 Error! stop

Если бы инструкций try…except не было, то при выбросе любого из исключений программа аварийно завершится.

print("start")
val = int(input(“input number: “))
tmp = 10 / val
print(tmp)
print("stop")

Если ввести 0 на запрос приведенной выше программы, произойдет ее остановка с распечаткой сообщения об исключении.

start


input number: 0


Traceback (most recent call last):


 File “F:/work/programming/python/devpractice/tmp.py”, line 3, in <module>


   tmp = 10 / val


ZeroDivisionError: division by zero

Обратите внимание, надпись stop уже не печатается в конце вывода программы.

Согласно документу по языку Python, описывающему ошибки и исключения, оператор try работает следующим образом:

  • Вначале выполняется код, находящийся между операторами try и except.
  • Если в ходе его выполнения исключения не произошло, то код в блоке except пропускается, а код в блоке try выполняется весь до конца.
  • Если исключение происходит, то выполнение в рамках блока try прерывается и выполняется код в блоке except. При этом для оператора except можно указать, какие исключения можно обрабатывать в нем. При возникновении исключения, ищется именно тот блок except, который может обработать данное исключение.
  • Если среди except блоков нет подходящего для обработки исключения, то оно передается наружу из блока try. В случае, если обработчик исключения так и не будет найден, то исключение будет необработанным (unhandled exception) и программа аварийно остановится.

Для указания набора исключений, который должен обрабатывать данный блок except их необходимо перечислить в скобках (круглых) через запятую после оператора except.

Если бы мы в нашей программе хотели обрабатывать только ValueError и ZeroDivisionError, то программа выглядела бы так.

print("start")
try:
   val = int(input("input number: "))
   tmp = 10 / val
   print(tmp)
except(ValueError, ZeroDivisionError):
   print("Error!")
print("stop")

Или так, если хотим обрабатывать ValueError, ZeroDivisionError по отдельность, и, при этом, сохранить работоспособность при возникновении исключений отличных от вышеперечисленных.

print("start")
try:
   val = int(input("input number: "))
   tmp = 10 / val
   print(tmp)
except ValueError:
   print("ValueError!")
except ZeroDivisionError:
   print("ZeroDivisionError!")
except:
   print("Error!")
print("stop")

Существует возможность передать подробную информацию о произошедшем исключении в код внутри блока except.

rint("start")
try:
   val = int(input("input number: "))
   tmp = 10 / val
   print(tmp)
except ValueError as ve:
   print("ValueError! {0}".format(ve))
except ZeroDivisionError as zde:
   print("ZeroDivisionError! {0}".format(zde))
except Exception as ex:
   print("Error! {0}".format(ex))
print("stop")

Использование finally в обработке исключений

Для выполнения определенного программного кода при выходе из блока try/except, используйте оператор finally.

try:
   val = int(input("input number: "))
   tmp = 10 / val
   print(tmp)
except:
   print("Exception")
finally:
  print("Finally code")

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

Если необходимо выполнить какой-то программный код, в случае если в процессе выполнения блока try не возникло исключений, то можно использовать оператор else.

try:
   f = open("tmp.txt", "r")
   for line in f:
       print(line)
   f.close()
except Exception as e:
   print(e)
else:
   print("File was readed")

Генерация исключений в Python

Для принудительной генерации исключения используется инструкция raise.

Самый простой пример работы с raise может выглядеть так.

try:
   raise Exception("Some exception")
except Exception as e:
   print("Exception exception " + str(e))

Таким образом, можно “вручную” вызывать исключения при необходимости.

Пользовательские исключения (User-defined Exceptions) в Python

В Python можно создавать собственные исключения. Такая практика позволяет увеличить гибкость процесса обработки ошибок в рамках той предметной области, для которой написана ваша программа.

Для реализации собственного типа исключения необходимо создать класс, являющийся наследником от одного из классов исключений.

class NegValException(Exception):
   pass

try:
   val = int(input("input positive number: "))
   if val < 0:
       raise NegValException("Neg val: " + str(val))
   print(val + 10)
except NegValException as e:
  print(e)

P.S.

Если вам интересна тема анализа данных, то мы рекомендуем ознакомиться с библиотекой Pandas. На нашем сайте вы можете найти вводные уроки по этой теме. Все уроки по библиотеке Pandas собраны в книге “Pandas. Работа с данными”.
Книга: Pandas. Работа с данными

<<< Python. Урок 10. Функции в Python   Python. Урок 12. Ввод-вывод данных. Работа с файлами>>>

Содержание:

  • Базовый класс для встроенных исключений BaseException,
  • Базовый класс пользовательских исключений Exception,
  • Базовый класс арифметических исключений ArithmeticError,
  • Базовый класс исключений связанных с буфером BufferError,
  • Базовый класс исключений связанных с индексированием LookupError,

BaseException:

Базовый класс для всех встроенных исключений. Он не предназначен для прямого наследования определяемыми пользователем классами, для этого используйте исключение Exception. Если функция str() вызывается на экземпляре этого класса, то возвращается представление аргумента(ов) к экземпляру или пустая строка, когда аргументов не было.

Атрибуты и методы BaseException:

BaseException.args:

Атрибут BaseException.args представляет собой кортеж аргументов, заданных конструктору исключений. Некоторые встроенные исключения (например, OSError) ожидают определенного числа аргументов и присваивают особое значение элементам этого кортежа, в то время как другие обычно вызываются только с одной строкой, дающей сообщение об ошибке.

BaseException.with_traceback(tb):

Метод BaseException.with_traceback(tb) устанавливает аргумент tb в качестве новой обратной трассировки для исключения и возвращает объект исключения. Он обычно используется в коде обработки исключений, как это:

try:
     ... 
 except SomeException:
     tb = sys.exc_info()[2]
     raise OtherException(...).with_traceback(tb)
BaseException.add_note(note):

Метод BaseException.add_note() добавляет строку примечания к примечаниям исключения, которые появляются в стандартной трассировке после строки исключения. Ошибка TypeError возникает, если аргумент note не является строкой.

Добавлен в Python 3.11.

BaseException.__notes__:

Атрибут BaseException.__notes__ — это список заметок этого исключения, которые были добавлены с помощью BaseException.add_note(). Этот атрибут создается при вызове метода BaseException.add_note().

Добавлен в Python 3.11.

Exception:

ArithmeticError:

Исключение ArithmeticError это базовый класс для трех встроенных исключений, которые поднимаются для различных арифметических ошибок:

  • OverflowError,
  • ZeroDivisionError,
  • FloatingPointError.

BufferError:

Исключение BufferError поднимается, когда операция, связанная с буфером, не может быть выполнена.

LookupError:

Исключение LookupError это базовый класс для исключений, которые возникают, когда ключ или индекс, используемые в отображении или последовательности, недопустимы: IndexError, KeyError. Исключение LookupError можно поднять напрямую codecs.lookup().

Содержание:развернуть

  • Как устроен механизм исключений
  • Как обрабатывать исключения в Python (try except)
  • As — сохраняет ошибку в переменную

  • Finally — выполняется всегда

  • Else — выполняется когда исключение не было вызвано

  • Несколько блоков except

  • Несколько типов исключений в одном блоке except

  • Raise — самостоятельный вызов исключений

  • Как пропустить ошибку

  • Исключения в lambda функциях
  • 20 типов встроенных исключений в Python
  • Как создать свой тип Exception

Программа, написанная на языке Python, останавливается сразу как обнаружит ошибку. Ошибки могут быть (как минимум) двух типов:

  • Синтаксические ошибки — возникают, когда написанное выражение не соответствует правилам языка (например, написана лишняя скобка);
  • Исключения — возникают во время выполнения программы (например, при делении на ноль).

Синтаксические ошибки исправить просто (если вы используете IDE, он их подсветит). А вот с исключениями всё немного сложнее — не всегда при написании программы можно сказать возникнет или нет в данном месте исключение. Чтобы приложение продолжило работу при возникновении проблем, такие ошибки нужно перехватывать и обрабатывать с помощью блока try/except.

Как устроен механизм исключений

В Python есть встроенные исключения, которые появляются после того как приложение находит ошибку. В этом случае текущий процесс временно приостанавливается и передает ошибку на уровень вверх до тех пор, пока она не будет обработано. Если ошибка не будет обработана, программа прекратит свою работу (а в консоли мы увидим Traceback с подробным описанием ошибки).

💁‍♂️ Пример: напишем скрипт, в котором функция ожидает число, а мы передаём сроку (это вызовет исключение «TypeError»):

def b(value):
print("-> b")
print(value + 1) # ошибка тут

def a(value):
print("-> a")
b(value)

a("10")

> -> a
> -> b
> Traceback (most recent call last):
> File "test.py", line 11, in <module>
> a("10")
> File "test.py", line 8, in a
> b(value)
> File "test.py", line 3, in b
> print(value + 1)
> TypeError: can only concatenate str (not "int") to str

В данном примере мы запускаем файл «test.py» (через консоль). Вызывается функция «a«, внутри которой вызывается функция «b«. Все работает хорошо до сточки print(value + 1). Тут интерпретатор понимает, что нельзя конкатенировать строку с числом, останавливает выполнение программы и вызывает исключение «TypeError».

Далее ошибка передается по цепочке в обратном направлении: «b» → «a» → «test.py«. Так как в данном примере мы не позаботились обработать эту ошибку, вся информация по ошибке отобразится в консоли в виде Traceback.

Traceback (трассировка) — это отчёт, содержащий вызовы функций, выполненные в определенный момент. Трассировка помогает узнать, что пошло не так и в каком месте это произошло.

Traceback лучше читать снизу вверх ↑

Пример Traceback в Python

В нашем примере Traceback содержится следующую информацию (читаем снизу вверх):

  1. TypeError — тип ошибки (означает, что операция не может быть выполнена с переменной этого типа);
  2. can only concatenate str (not "int") to str — подробное описание ошибки (конкатенировать можно только строку со строкой);
  3. Стек вызова функций (1-я линия — место, 2-я линия — код). В нашем примере видно, что в файле «test.py» на 11-й линии был вызов функции «a» со строковым аргументом «10». Далее был вызов функции «b». print(value + 1) это последнее, что было выполнено — тут и произошла ошибка.
  4. most recent call last — означает, что самый последний вызов будет отображаться последним в стеке (в нашем примере последним выполнился print(value + 1)).

В Python ошибку можно перехватить, обработать, и продолжить выполнение программы — для этого используется конструкция try ... except ....

Как обрабатывать исключения в Python (try except)

В Python исключения обрабатываются с помощью блоков try/except. Для этого операция, которая может вызвать исключение, помещается внутрь блока try. А код, который должен быть выполнен при возникновении ошибки, находится внутри except.

Например, вот как можно обработать ошибку деления на ноль:

try:
a = 7 / 0
except:
print('Ошибка! Деление на 0')

Здесь в блоке try находится код a = 7 / 0 — при попытке его выполнить возникнет исключение и выполнится код в блоке except (то есть будет выведено сообщение «Ошибка! Деление на 0»). После этого программа продолжит свое выполнение.

💭 PEP 8 рекомендует, по возможности, указывать конкретный тип исключения после ключевого слова except (чтобы перехватывать и обрабатывать конкретные исключения):

try:
a = 7 / 0
except ZeroDivisionError:
print('Ошибка! Деление на 0')

Однако если вы хотите перехватывать все исключения, которые сигнализируют об ошибках программы, используйте тип исключения Exception:

try:
a = 7 / 0
except Exception:
print('Любая ошибка!')

As — сохраняет ошибку в переменную

Перехваченная ошибка представляет собой объект класса, унаследованного от «BaseException». С помощью ключевого слова as можно записать этот объект в переменную, чтобы обратиться к нему внутри блока except:

try:
file = open('ok123.txt', 'r')
except FileNotFoundError as e:
print(e)

> [Errno 2] No such file or directory: 'ok123.txt'

В примере выше мы обращаемся к объекту класса «FileNotFoundError» (при выводе на экран через print отобразится строка с полным описанием ошибки).

У каждого объекта есть поля, к которым можно обращаться (например если нужно логировать ошибку в собственном формате):

import datetime

now = datetime.datetime.now().strftime("%d-%m-%Y %H:%M:%S")

try:
file = open('ok123.txt', 'r')
except FileNotFoundError as e:
print(f"{now} [FileNotFoundError]: {e.strerror}, filename: {e.filename}")

> 20-11-2021 18:42:01 [FileNotFoundError]: No such file or directory, filename: ok123.txt

Finally — выполняется всегда

При обработке исключений можно после блока try использовать блок finally. Он похож на блок except, но команды, написанные внутри него, выполняются обязательно. Если в блоке try не возникнет исключения, то блок finally выполнится так же, как и при наличии ошибки, и программа возобновит свою работу.

Обычно try/except используется для перехвата исключений и восстановления нормальной работы приложения, а try/finally для того, чтобы гарантировать выполнение определенных действий (например, для закрытия внешних ресурсов, таких как ранее открытые файлы).

В следующем примере откроем файл и обратимся к несуществующей строке:

file = open('ok.txt', 'r')

try:
lines = file.readlines()
print(lines[5])
finally:
file.close()
if file.closed:
print("файл закрыт!")

> файл закрыт!
> Traceback (most recent call last):
> File "test.py", line 5, in <module>
> print(lines[5])
> IndexError: list index out of range

Даже после исключения «IndexError», сработал код в секции finally, который закрыл файл.

p.s. данный пример создан для демонстрации, в реальном проекте для работы с файлами лучше использовать менеджер контекста with.

Также можно использовать одновременно три блока try/except/finally. В этом случае:

  • в try — код, который может вызвать исключения;
  • в except — код, который должен выполниться при возникновении исключения;
  • в finally — код, который должен выполниться в любом случае.

def sum(a, b):
res = 0

try:
res = a + b
except TypeError:
res = int(a) + int(b)
finally:
print(f"a = {a}, b = {b}, res = {res}")

sum(1, "2")

> a = 1, b = 2, res = 3

Else — выполняется когда исключение не было вызвано

Иногда нужно выполнить определенные действия, когда код внутри блока try не вызвал исключения. Для этого используется блок else.

Допустим нужно вывести результат деления двух чисел и обработать исключения в случае попытки деления на ноль:

b = int(input('b = '))
c = int(input('c = '))
try:
a = b / c
except ZeroDivisionError:
print('Ошибка! Деление на 0')
else:
print(f"a = {a}")

> b = 10
> c = 1
> a = 10.0

В этом случае, если пользователь присвоит переменной «с» ноль, то появится исключение и будет выведено сообщение «‘Ошибка! Деление на 0′», а код внутри блока else выполняться не будет. Если ошибки не будет, то на экране появятся результаты деления.

Несколько блоков except

В программе может возникнуть несколько исключений, например:

  1. Ошибка преобразования введенных значений к типу float («ValueError»);
  2. Деление на ноль («ZeroDivisionError»).

В Python, чтобы по-разному обрабатывать разные типы ошибок, создают несколько блоков except:

try:
b = float(input('b = '))
c = float(input('c = '))
a = b / c
except ZeroDivisionError:
print('Ошибка! Деление на 0')
except ValueError:
print('Число введено неверно')
else:
print(f"a = {a}")

> b = 10
> c = 0
> Ошибка! Деление на 0

> b = 10
> c = питон
> Число введено неверно

Теперь для разных типов ошибок есть свой обработчик.

Несколько типов исключений в одном блоке except

Можно также обрабатывать в одном блоке except сразу несколько исключений. Для этого они записываются в круглых скобках, через запятую сразу после ключевого слова except. Чтобы обработать сообщения «ZeroDivisionError» и «ValueError» в одном блоке записываем их следующим образом:

try:
b = float(input('b = '))
c = float(input('c = '))
a = b / c
except (ZeroDivisionError, ValueError) as er:
print(er)
else:
print('a = ', a)

При этом переменной er присваивается объект того исключения, которое было вызвано. В результате на экран выводятся сведения о конкретной ошибке.

Raise — самостоятельный вызов исключений

Исключения можно генерировать самостоятельно — для этого нужно запустить оператор raise.

min = 100
if min > 10:
raise Exception('min must be less than 10')

> Traceback (most recent call last):
> File "test.py", line 3, in <module>
> raise Exception('min value must be less than 10')
> Exception: min must be less than 10

Перехватываются такие сообщения точно так же, как и остальные:

min = 100

try:
if min > 10:
raise Exception('min must be less than 10')
except Exception:
print('Моя ошибка')

> Моя ошибка

Кроме того, ошибку можно обработать в блоке except и пробросить дальше (вверх по стеку) с помощью raise:

min = 100

try:
if min > 10:
raise Exception('min must be less than 10')
except Exception:
print('Моя ошибка')
raise

> Моя ошибка
> Traceback (most recent call last):
> File "test.py", line 5, in <module>
> raise Exception('min must be less than 10')
> Exception: min must be less than 10

Как пропустить ошибку

Иногда ошибку обрабатывать не нужно. В этом случае ее можно пропустить с помощью pass:

try:
a = 7 / 0
except ZeroDivisionError:
pass

Исключения в lambda функциях

Обрабатывать исключения внутри lambda функций нельзя (так как lambda записывается в виде одного выражения). В этом случае нужно использовать именованную функцию.

20 типов встроенных исключений в Python

Иерархия классов для встроенных исключений в Python выглядит так:

BaseException
SystemExit
KeyboardInterrupt
GeneratorExit
Exception
ArithmeticError
AssertionError
...
...
...
ValueError
Warning

Все исключения в Python наследуются от базового BaseException:

  • SystemExit — системное исключение, вызываемое функцией sys.exit() во время выхода из приложения;
  • KeyboardInterrupt — возникает при завершении программы пользователем (чаще всего при нажатии клавиш Ctrl+C);
  • GeneratorExit — вызывается методом close объекта generator;
  • Exception — исключения, которые можно и нужно обрабатывать (предыдущие были системными и их трогать не рекомендуется).

От Exception наследуются:

1 StopIteration — вызывается функцией next в том случае если в итераторе закончились элементы;

2 ArithmeticError — ошибки, возникающие при вычислении, бывают следующие типы:

  • FloatingPointError — ошибки при выполнении вычислений с плавающей точкой (встречаются редко);
  • OverflowError — результат вычислений большой для текущего представления (не появляется при операциях с целыми числами, но может появиться в некоторых других случаях);
  • ZeroDivisionError — возникает при попытке деления на ноль.

3 AssertionError — выражение, используемое в функции assert неверно;

4 AttributeError — у объекта отсутствует нужный атрибут;

5 BufferError — операция, для выполнения которой требуется буфер, не выполнена;

6 EOFError — ошибка чтения из файла;

7 ImportError — ошибка импортирования модуля;

8 LookupError — неверный индекс, делится на два типа:

  • IndexError — индекс выходит за пределы диапазона элементов;
  • KeyError — индекс отсутствует (для словарей, множеств и подобных объектов);

9 MemoryError — память переполнена;

10 NameError — отсутствует переменная с данным именем;

11 OSError — исключения, генерируемые операционной системой:

  • ChildProcessError — ошибки, связанные с выполнением дочернего процесса;
  • ConnectionError — исключения связанные с подключениями (BrokenPipeError, ConnectionResetError, ConnectionRefusedError, ConnectionAbortedError);
  • FileExistsError — возникает при попытке создания уже существующего файла или директории;
  • FileNotFoundError — генерируется при попытке обращения к несуществующему файлу;
  • InterruptedError — возникает в том случае если системный вызов был прерван внешним сигналом;
  • IsADirectoryError — программа обращается к файлу, а это директория;
  • NotADirectoryError — приложение обращается к директории, а это файл;
  • PermissionError — прав доступа недостаточно для выполнения операции;
  • ProcessLookupError — процесс, к которому обращается приложение не запущен или отсутствует;
  • TimeoutError — время ожидания истекло;

12 ReferenceError — попытка доступа к объекту с помощью слабой ссылки, когда объект не существует;

13 RuntimeError — генерируется в случае, когда исключение не может быть классифицировано или не подпадает под любую другую категорию;

14 NotImplementedError — абстрактные методы класса нуждаются в переопределении;

15 SyntaxError — ошибка синтаксиса;

16 SystemError — сигнализирует о внутренне ошибке;

17 TypeError — операция не может быть выполнена с переменной этого типа;

18 ValueError — возникает когда в функцию передается объект правильного типа, но имеющий некорректное значение;

19 UnicodeError — исключение связанное с кодирование текста в unicode, бывает трех видов:

  • UnicodeEncodeError — ошибка кодирования;
  • UnicodeDecodeError — ошибка декодирования;
  • UnicodeTranslateError — ошибка перевода unicode.

20 Warning — предупреждение, некритическая ошибка.

💭 Посмотреть всю цепочку наследования конкретного типа исключения можно с помощью модуля inspect:

import inspect

print(inspect.getmro(TimeoutError))

> (<class 'TimeoutError'>, <class 'OSError'>, <class 'Exception'>, <class 'BaseException'>, <class 'object'>)

📄 Подробное описание всех классов встроенных исключений в Python смотрите в официальной документации.

Как создать свой тип Exception

В Python можно создавать свои исключения. При этом есть одно обязательное условие: они должны быть потомками класса Exception:

class MyError(Exception):
def __init__(self, text):
self.txt = text

try:
raise MyError('Моя ошибка')
except MyError as er:
print(er)

> Моя ошибка


С помощью try/except контролируются и обрабатываются ошибки в приложении. Это особенно актуально для критически важных частей программы, где любые «падения» недопустимы (или могут привести к негативным последствиям). Например, если программа работает как «демон», падение приведет к полной остановке её работы. Или, например, при временном сбое соединения с базой данных, программа также прервёт своё выполнение (хотя можно было отловить ошибку и попробовать соединиться в БД заново).

Вместе с try/except можно использовать дополнительные блоки. Если использовать все блоки описанные в статье, то код будет выглядеть так:

try:
# попробуем что-то сделать
except (ZeroDivisionError, ValueError) as e:
# обрабатываем исключения типа ZeroDivisionError или ValueError
except Exception as e:
# исключение не ZeroDivisionError и не ValueError
# поэтому обрабатываем исключение общего типа (унаследованное от Exception)
# сюда не сходят исключения типа GeneratorExit, KeyboardInterrupt, SystemExit
else:
# этот блок выполняется, если нет исключений
# если в этом блоке сделать return, он не будет вызван, пока не выполнился блок finally
finally:
# этот блок выполняется всегда, даже если нет исключений else будет проигнорирован
# если в этом блоке сделать return, то return в блоке

Подробнее о работе с исключениями в Python можно ознакомиться в официальной документации.

  • Исключения — это сценарии ошибок, которые изменяют нормальный поток выполнения программы.
  • Процесс обработки возможных исключений называется обработкой исключений.
  • Если исключения не обрабатываются должным образом, программа может завершиться преждевременно. Это может привести к повреждению данных или нежелательным результатам.
  • Обработка исключений Python достигается тремя блоками ключевых слов — try, except и finally.
  • Блок try содержит код, который может вызывать исключения или ошибки.
  • Блок except используется для перехвата исключений и их обработки.
  • Код блока catch выполняется только при возникновении соответствующего исключения.
  • Может быть несколько блоков catch. Мы также можем поймать несколько исключений в одном блоке catch.
  • Код блока finally всегда выполняется независимо от того, правильно ли выполнялась программа или возникла исключительная ситуация.
  • Мы также можем создать блок else с блоком try-except. Код внутри блока else выполняется, если не возникают исключения.

Давайте посмотрим на пример.

def divide(x, y):
    print(f'{x}/{y} is {x / y}')


divide(10, 2)
divide(10, 0)
divide(10, 4)

Если мы запустим указанную выше программу, мы получим следующий результат.

10/2 is 5.0
Traceback (most recent call last):
  File "/Users/pankaj/Documents/PycharmProjects/PythonTutorialPro/hello-world/exception_handling.py", line 6, in <module>
    divide(10, 0)
  File "/Users/pankaj/Documents/PycharmProjects/PythonTutorialPro/hello-world/exception_handling.py", line 2, in divide
    print(f'{x}/{y} is {x / y}')
ZeroDivisionError: division by zero

Второй вызов функции div() вызвал исключение ZeroDivisionError, и программа завершилась.

Мы так и не получили результат третьего вызова метода DivX(), потому что мы не выполняли обработку исключений в нашем коде.

Давайте перепишем метод div() с правильной обработкой исключений. Если кто-то попытается разделить на 0, мы перехватим исключение и выведем сообщение об ошибке. Таким образом, программа не завершится преждевременно, и вывод будет более понятным.

def divide(x, y):
    try:
        print(f'{x}/{y} is {x / y}')
    except ZeroDivisionError as e:
        print(e)


divide(10, 2)
divide(10, 0)
divide(10, 4)

Вывод:

10/2 is 5.0
division by zero
10/4 is 2.5

Обработка Исключений Python

Что такое класс BaseException?

Класс BaseException — это базовый класс всех исключений. Он имеет четыре подкласса.

  1. Исключение-это базовый класс для всех исключений, не связанных с выходом.
  2. GeneratorExit-запрос на выход генератора.
  3. KeyboardInterrupt-программа, прерванная пользователем.
  4. SystemExit-запрос на выход из интерпретатора.

Встроенные классы исключений

Вот некоторые из встроенных классов исключений в Python:

  • ArithmeticError — это базовый класс для арифметических ошибок.
  • AssertionError — возникает, когда утверждение не выполняется.
  • AttributeError — когда атрибут не найден.
  • BufferError
  • EOFError — чтение после конца файла
  • ImportError — когда импортированный модуль не найден.
  • LookupError — базовое исключение для ошибок поиска.
  • MemoryError — при нехватке памяти
  • NameError — когда имя не найдено глобально.
  • OSError — базовый класс для ошибок ввода-вывода
  • ReferenceError
  • Ошибка выполнения
  • StopIteration, StopAsyncIteration
  • SyntaxError — недопустимый синтаксис
  • SystemError — внутренняя ошибка интерпретатора Python.
  • TypeError — недопустимый тип аргумента
  • ValueError — недопустимое значение аргумента

Встроенные классы предупреждений

Класс Warning — это базовый класс для всех предупреждений. Он имеет следующие подклассы.

  • BytesWarning — предупреждения, связанные с байтами и буфером, в основном связанные с преобразованием и сравнением строк.
  • DeprecationWarning — предупреждение об устаревших функциях
  • FutureWarning — базовый класс для предупреждения о конструкциях, которые будут семантически изменяться в будущем.
  • ImportWarning — предупреждение об ошибках при импорте модулей
  • PendingDeprecationWarning — предупреждение о функциях, поддержка которых в будущем будет прекращена.
  • ResourceWarning — предупреждения об использовании ресурсов
  • RuntimeWarning — предупреждения о сомнительном поведении во время выполнения.
  • SyntaxWarning — предупреждение о сомнительном синтаксисе
  • UnicodeWarning — предупреждения, связанные с преобразованием Unicode
  • UserWarning — предупреждения, генерируемые кодом пользователя

Обработка нескольких исключений в одном блоке Except

Блок try может иметь несколько блоков except. Мы можем поймать определенные исключения в каждом из блоков except.

def divide(x, y):
    try:
        print(f'{x}/{y} is {x / y}')
    except ZeroDivisionError as e:
        print(e)
    except TypeError as e:
        print(e)
    except ValueError as e:
        print(e)

Код в каждом блоке except одинаковый. В этом сценарии мы можем обрабатывать несколько исключений в одном блоке except. Мы можем передать кортеж объектов исключения в блок except, чтобы поймать несколько исключений.

def divide(x, y):
    try:
        print(f'{x}/{y} is {x / y}')
    except (ZeroDivisionError, TypeError, ValueError) as e:
        print(e)

Поймать все исключения в блоке с одним исключением

Если мы не укажем какой-либо класс исключения в блоке except, он перехватит все исключения, вызванные блоком try. Это полезно, когда мы не знаем об исключениях, которые может вызвать блок try.

Пустое предложение except должно быть последним.

def divide(x, y):
    try:
        print(f'{x}/{y} is {x / y}')
    except ZeroDivisionError as e:
        print(e)
    except:
        print("unknown error occurred")

Использование else Block с try-except

Код блока else не является обязательным. Он выполняется, когда нет исключений, вызванных блоком try.

def divide(x, y):
    try:
        print(f'{x}/{y} is {x / y}')
    except ZeroDivisionError as e:
        print(e)
    else:
        print("divide() function worked fine.")


divide(10, 2)
divide(10, 0)
divide(10, 4)

Вывод:

Try Except Else пример

Код блока else выполняется дважды, когда блок try функции div() работал без каких-либо исключений.

Использование finally Block с try-except

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

def divide(x, y):
    try:
        print(f'{x}/{y} is {x / y}')
    except ZeroDivisionError as e:
        print(e)
    else:
        print("divide() function worked fine.")
    finally:
        print("close all the resources here")


divide(10, 2)
divide(10, 0)
divide(10, 4)

Вывод:

Try Except Else Finally блок

Синтаксис

окончательный синтаксис таков:

try -> except 1...n -> else -> finally

У нас может быть много блоков except для блока try. Но у нас может быть только еще один else, finally блок.

Создание настраиваемого класса исключения

Мы можем создать собственный класс исключения, расширив класс Exception. Лучше всего создать базовое исключение, а затем наследовать другие классы. Вот несколько примеров.

class EmployeeModuleError(Exception):
    """Base Exception Class for our Employee module"""
    pass


class EmployeeNotFoundError(EmployeeModuleError):
    """Error raised when employee is not found in the database"""

    def __init__(self, emp_id, msg):
        self.employee_id = emp_id
        self.error_message = msg


class EmployeeUpdateError(EmployeeModuleError):
    """Error raised when employee update fails"""

    def __init__(self, emp_id, sql_error_code, sql_error_msg):
        self.employee_id = emp_id
        self.error_message = sql_error_msg
        self.error_code = sql_error_code

По соглашению об именах к имени класса исключения добавляется суффикс «Ошибка».

Вызов исключений

Мы можем использовать ключевое слово raise, чтобы генерировать исключение из нашего кода. Некоторые из возможных сценариев:

  • Ошибка проверки входных параметров функции;
  • Поймать исключение и затем выбросить собственное.
class ValidationError(Exception):
    pass


def divide(x, y):
    try:
        if type(x) is not int:
            raise TypeError("Unsupported type")
        if type(y) is not int:
            raise TypeError("Unsupported type")
    except TypeError as e:
        print(e)
        raise ValidationError("Invalid type of arguments")

    if y is 0:
        raise ValidationError("We can't divide by 0.")


try:
    divide(10, 0)
except ValidationError as ve:
    print(ve)

try:
    divide(10, "5")
except ValidationError as ve:
    print(ve)

Вывод:

We can't divide by 0.
Unsupported type
Invalid type of arguments

Пример вложенных блоков try-except

У нас могут быть вложенные блоки try-except в Python. В этом случае, если во вложенном блоке try возникает исключение, для его обработки используется вложенный блок except. В случае, если вложенный объект except не может его обработать, для обработки исключения используются внешние блоки except.

x = 10
y = 0

try:
    print("outer try block")
    try:
        print("nested try block")
        print(x / y)
    except TypeError as te:
        print("nested except block")
        print(te)
except ZeroDivisionError as ze:
    print("outer except block")
    print(ze)

Вывод:

outer try block
nested try block
outer except block
division by zero

Советы

  • Всегда пытайтесь обработать исключение в коде, чтобы избежать аварийного завершения программы.
  • При создании настраиваемого класса исключения добавьте к его имени суффикс «Error».
  • Если в предложениях except одинаковый код, попробуйте перехватить несколько исключений в одном блоке except.
  • Используйте блок finally, чтобы закрыть тяжелые ресурсы.
  • Используйте блок else для регистрации успешного выполнения кода, отправки уведомлений и т. д.
  • По возможности избегайте голых исключений.
  • Создавайте классы исключений для конкретных модулей для конкретных сценариев.
  • Вы можете перехватить исключения в блоке except, а затем вызвать другое, которое будет более значимым.
  • Всегда вызывайте с осмысленными сообщениями.
  • Избегайте вложенных блоков try-except, потому что это снижает читаемость кода.

Последнее обновление: 30.01.2022

Встроенные типы исключений

В примере выше обрабатывались сразу все исключения, которые могут возникнуть в коде. Однако мы можем конкретизировать тип обрабатываемого исключения,
указав его после слова except:

try:
    number = int(input("Введите число: "))
    print("Введенное число:", number)
except ValueError:
    print("Преобразование прошло неудачно")
print("Завершение программы")

В данном случае блок execpt обрабатывает только исключения типа ValueError, которые могут возникнут при неудачном преобразовании
строки в число.

В Python есть следующие базовые типы исключений:

  • BaseException: базовый тип для всех встроенных исключений

  • Exception: базовый тип, который обычно применяется для создания своих типов исключений

  • ArithmeticError: базовый тип для исключений, связанных с арифметическими операциями (OverflowError, ZeroDivisionError, FloatingPointError).

  • BufferError: тип исключения, которое возникает при невозможности выполнить операцию с буффером

  • LookupError: базовый тип для исключений, которое возникают при обращении в коллекциях по некорректному ключу или индексу
    (например, IndexError, KeyError)

От этих классов наследуются все конкретные типы исключений. В Python обладает довольно большим списком встроенных исключений. Весь этот список можно
посмотреть в документации. Перечислю только некоторые наиболее часто встречающиеся:

  • IndexError: исключение возникает, если индекс при обращении к элементу коллекции находится вне допустимого диапазона

  • KeyError: возникает, если в словаре отсутствует ключ, по которому происходит обращение к элементу словаря.

  • OverflowError: возникает, если результат арифметической операции не может быть представлен текущим числовым типом (обычно типом float).

  • RecursionError: возникает, если превышена допустимая глубина рекурсии.

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

  • ValueError: возникает, если операция или функция получают объект корректного типа с некорректным значением.

  • ZeroDivisionError: возникает при делении на ноль.

  • NotImplementedError: тип исключения для указания, что какие-то методы класса не реализованы

  • ModuleNotFoundError: возникает при при невозможности найти модуль при его импорте директивой import

  • OSError: тип исключений, которые генерируются при возникновении ошибок системы (например, невозможно найти файл, память диска заполнена и т.д.)

И если ситуация такова, что в программе могут быть сгенерированы различные типы исключений, то мы можем их обработать по отдельности, используя дополнительные
выражения except. И при возникновении исключения Python будет искать нужный блок except, который обрабатывает данный тип исключения:

try:
    number1 = int(input("Введите первое число: "))
    number2 = int(input("Введите второе число: "))
    print("Результат деления:", number1/number2)
except ValueError:
    print("Преобразование прошло неудачно")
except ZeroDivisionError:
    print("Попытка деления числа на ноль")
except BaseException:
    print("Общее исключение")
print("Завершение программы")

Если возникнет исключение в результате преобразования строки в число, то оно будет обработано блоком except ValueError.
Если же второе число будет равно нулю, то есть будет деление на ноль, тогда возникнет исключение ZeroDivisionError, и оно будет обработано блоком
except ZeroDivisionError.

Тип BaseException представляет общее исключение, под которое попадают все исключительные ситуации. Поэтому в данном случае
любое исключение, которое не представляет тип ValueError или ZeroDivisionError, будет обработано в блоке except BaseException:.

Однако, если в программе возникает исключение типа, для которого нет соответствующего блока except, то программа не сможет найти соответствующий блок except и
сгенерирует исключение. Например, в следующем случае:

try:
    number1 = int(input("Введите первое число: "))
    number2 = int(input("Введите второе число: "))
    print("Результат деления:", number1/number2)
except ZeroDivisionError:
    print("Попытка деления числа на ноль")
print("Завершение программы")

Здесь предусмотрена обработка деления на ноль с помощью блока except ZeroDivisionError. Однако если пользователь вместо числа введет некорвертиуремую в число в строку, то
возникнет исключение типа ValueError, для которого нет соответствующего блока except. И поэтому программа аварийно завершит свое выполнение.

Python позволяет в одном блоке except обрабатывать сразу несколько типов исключений. В этом случае все типы исключения передаются в скобках:

try:
    number1 = int(input("Введите первое число: "))
    number2 = int(input("Введите второе число: "))
    print("Результат деления:", number1/number2)
except (ZeroDivisionError, ValueError):    #  обработка двух типов исключений - ZeroDivisionError и ValueError
    print("Попытка деления числа на ноль или некорректный ввод")

print("Завершение программы")

Получение информации об исключении

С помощью оператора as мы можем передать всю информацию об исключении в переменную, которую затем можно использовать в блоке except:

try:
    number = int(input("Введите число: "))
    print("Введенное число:", number)
except ValueError as e:
    print("Сведения об исключении", e)
print("Завершение программы")

Пример некорректного ввода:

Введите число: fdsf
Сведения об исключении invalid literal for int() with base 10: 'fdsf'
Завершение программы

0 0 голоса
Рейтинг статьи
Подписаться
Уведомить о
guest

0 комментариев
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии

А вот еще интересные материалы:

  • Яшка сломя голову остановился исправьте ошибки
  • Ясность цели позволяет целеустремленно добиваться намеченного исправьте ошибки
  • Ясность цели позволяет целеустремленно добиваться намеченного где ошибка
  • Pyscripter could not load a python engine ошибка
  • Pyqt5 диалоговое окно ошибки