Исключения в Python — примеры обработки

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

Что такое исключения в Python?

В Python исключения — это объекты классов исключений. Все классы исключений являются подклассами класса BaseException.

Однако почти все встроенные классы исключений наследуются от класса Exception, который является подклассом класса BaseException:

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

На этой странице показана полная иерархия классов для встроенных исключений в Python.

В следующем примере определяется список из трех элементов и делается попытка доступа к четвертому:

colors = ['red', 'green', 'blue']

print(colors[3])

Недопустимый индекс вызвал, как и ожидалось, исключение IndexError:

IndexError: list index out of range

При возникновении исключения Python останавливает программу, пока вы его не обработаете. Чтобы обработать исключение, используйте оператор try…except. Например:

colors = ['red', 'green', 'blue']

try:
    print(colors[3])
except IndexError as e:
    print(e)


print('Continue to run')

Выход:

<class 'IndexError'> - list index out of range
Continue to run

В этом примере мы используем try…except для обработки исключения IndexError. Как видно из вывода, программа после этого продолжает работать.

Класс IndexError наследуется от класса LookupError, который в свою очередь наследуется от класса Exception:

Схема наследия класса IndexError

И вы можете перехватить класс LookupError или Exception, когда возникает исключение IndexError. Например:

colors = ['red', 'green', 'blue']

try:
    print(colors[3])
except LookupError as e:
    print(e.__class__, '-', e)

print('Continue to run')

Выход:

<class 'IndexError'> - list index out of range
Continue to run

В этом примере исключением по-прежнему является IndexError, даже несмотря на то, что мы перехватываем исключение LookupError. Таким образом, когда вы обрабатываете исключение, обработчик исключений перехватывает указанный вами тип исключения и любой из его подклассов.

Программа работает так же, если вы используете класс Exception вместо класса LookupError:

colors = ['red', 'green', 'blue']

try:
    print(colors[3])
except Exception as e:
    print(e.__class__, '-', e)

print('Continue to run')

Выход:

<class 'IndexError'> - list index out of range
Continue to run

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

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

В следующем примере определяется функция division, которая возвращает результат деления a на b:

def division(a, b):
    return a / b


c = division(10, 0)

Выход:

ZeroDivisionError: division by zero

В этом примере, если b равно нулю, возникнет исключение ZeroDivisionError. Чтобы обработать исключение ZeroDivisionError, используйте оператор try…Exception следующим образом:

def division(a, b):
    try:
        return {
            'success': True,
            'message': 'OK',
            'result': a / b
        }
    except ZeroDivisionError as e:
        return {
            'success': False,
            'message': 'b cannot be zero',
            'result': None
        }


result = division(10, 0)
print(result)

В этом примере функция возвращает словарь, состоящий из трех элементов:

  • success — это логическое значение, которое указывает, успешна операция или нет.
  • message указывает на сообщение об ошибке или успехе.
  • result сохраняет результат a/b или None, если b равно нулю.

Ниже показан вывод в случае возникновения ошибки ZeroDivisionError:

{'success': False, 'message': 'b cannot be zero', 'result': None}

Теперь, если вы не улавливаете исключение ZeroDivisionError, а более общее исключение, например класс Exception:

def division(a, b):
    try:
        return {
            'success': True,
            'message': 'OK',
            'result': a / b
        }
    except Exception as e:
        return {
            'success': False,
            'message': 'b cannot be zero',
            'result': None
        }


result = division(10, 0)
print(result)

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

Однако если вы передадите в функцию division() две строки вместо двух чисел, вы получите то же сообщение, как если бы произошло исключение ZeroDivisionError:

def division(a, b):
    try:
        return {
            'success': True,
            'message': 'OK',
            'result': a / b
        }
    except Exception as e:
        return {
            'success': False,
            'message': 'b cannot be zero',
            'result': None
        }


result = division('10', '2')
print(result)

Выход:

{'success': False, 'message': 'b cannot be zero', 'result': None}

В этом примере исключением является не ZeroDivisionError, а TypeError. Однако код по-прежнему обрабатывает его как исключение ZeroDivisionError.

Поэтому вы всегда должны обрабатывать исключения от наиболее конкретных к наименее конкретным. Например:

def division(a, b):
    try:
        return {
            'success': True,
            'message': 'OK',
            'result': a / b
        }
    except TypeError as e:
        return {
            'success': False,
            'message': 'Both a & b must be numbers',
            'result': None
        }
    except ZeroDivisionError as e:
        return {
            'success': False,
            'message': 'b cannot be zero',
            'result': None
        }
    except Exception as e:
        return {
            'success': False,
            'message': str(e),
            'result': None
        }


result = division('10', '2')
print(result)

В этом примере мы перехватываем TypeError, ZeroDivisionError и Exception в том порядке, в котором они появляются в операторе try…except.

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

def division(a, b):
    try:
        return {
            'success': True,
            'message': 'OK',
            'result': a / b
        }
    except(TypeError, ZeroDivisionError, Exception) as e:
        return {
            'success': False,
            'message': str(e),
            'result': None
        }


result = division(10, 0)
print(result)

Выход:

{'success': False, 'message': 'division by zero', 'result': None}
Похожие посты
Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *