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

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

Содержание

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

Для обработки исключений вы используете оператор try. Оператор try состоит из следующих пунктов:

try:
    # code that you want to protect from exceptions
except <ExceptionType> as ex:
    # code that handle the exception
finally:
    # code that always execute whether the exception occurred or not
else:
    # code that excutes if try execute normally(an except clause must be present)

Давайте рассмотрим оператор try более подробно.

try

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

Предложение try появляется в операторе try ровно один раз.

except

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

В предложении «except» as ex не является обязательным. И также <ExceptionType> не является обязательным. Однако если вы опустите as ex, у вас будет простой обработчик исключений.

При указании типов исключений в предложениях except вы размещаете наиболее специфичные и наименее специфичные исключения сверху вниз.

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

try:
...
except <ExceptionType1> as ex:
    log(ex)
except <ExceptionType2> as ex:
    log(ex)

Становиться

try:
...
except(<ExceptionType1>, <ExceptionType2>) as ex:
    log(ex)

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

finally

Предложение «finally» может появляться в операторе try ноль или 1 раз. Предложение «finally» всегда выполняется независимо от того, возникло исключение или нет.

else

Предложение else также появляется ноль или 1 раз. И предложение else действует только в том случае, если в операторе try есть хотя бы одно предложение except.

Обычно вы размещаете код, который выполняется, если предложение try завершается нормально.

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

Ниже определяется функция, которая возвращает результат деления одного числа на другое:

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

Если вы передадите 0 второму аргументу, вы получите исключение ZeroDivisionError:

divide(10, 0)

Ошибка:

ZeroDivisionError: division by zero

Чтобы это исправить, вы можете обработать исключение ZeroDivisionError в функции divide() следующим образом:

def divide(a, b):
    try:
        return a / b
    except ZeroDivisionError as ex:
        return None

В этом примере функция divide() возвращает None, если возникает ошибка ZeroDivisionError:

def divide(a, b):
    try:
        return a / b
    except ZeroDivisionError as ex:
        return None

При использовании функции divide() вам необходимо проверить, равен ли результат None:

result = divide(10, 0)

if result is not None:
    print('result:', result)
else:
    print('Invalid inputs')

Но возврат None может быть не лучшим решением, поскольку другие могут случайно оценить результат в операторе if следующим образом:

result = divide(10, 0)

if result:
    print('result:', result)
else:
    print('Invalid inputs')

В этом случае это работает. Однако это не сработает, если первый аргумент равен нулю. Например:

result = divide(0, 10)

if result:
    print('result:', result)
else:
    print('Invalid inputs')

Лучший подход — вызвать исключение для вызывающей стороны, если произошло исключение ZeroDivisionError. Например:

def divide(a, b):
    try:
        return a / b
    except ZeroDivisionError as ex:
        raise ValueError('The second argument(b) must not be zero')

В этом примере функция divide() выдаст ошибку, если b равно нулю. Чтобы использовать функцию divide(), вам необходимо перехватить исключение ValueError:

def divide(a, b):
    try:
        return a / b
    except ZeroDivisionError as ex:
        raise ValueError('The second argument(b) must not be zero')


try:
    result = divide(10, 0)
except ValueError as e:
    print(e)
else:
    print('result:', result)

Выход:

The second argument(b) must not be zero

В особых случаях рекомендуется вызывать исключение вместо возврата None.

Пример порядка исключений

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

Ниже показаны три класса исключений: Exception, LookupError и IndexError:

Типы исключений

Если вы перехватываете исключение, вам необходимо разместить их в следующем порядке: IndexError, LookupErorr и Exception.

Например, следующее определяет список из трех строк и пытается получить доступ к 4-му элементу:

colors = ['red', 'green', 'blue']
try:
    print(colors[3])
except IndexError as e:
    print(type(e), 'Index error')
except LookupError as e:
    print(type(e), 'Lookup error')

Выдает следующую ошибку:

<class 'IndexError'> Index error

Доступ к цветам[3] вызывает исключение IndexError. Однако, если вы поменяете местами предложения исключений и сначала поймаете LookupError, а затем IndexError, вот так:

colors = ['red', 'green', 'blue']
try:
    print(colors[3])
except LookupError as e:
    print(type(e), 'Lookup error')
except IndexError as e:
    print(type(e), 'Index error')

Выход:

<class 'IndexError'> Lookup error

Исключением по-прежнему является IndexError, но следующее сообщение вводит в заблуждение.

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

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

try:
    ...
except:
    ...

Это эквивалентно следующему:

try:
    ...
except BaseException:

    ...

Простой обработчик исключений перехватывает любые исключения, включая SystemExit и KeyboardInterupt. Простое исключение затруднит прерывание программы с помощью Control-C и маскировку других программ.

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

try:
    ...
except Exception:
    ...

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

Чтобы получить информацию об исключении из простого обработчика исключений, используйте функцию exc_info() из модуля sys.

Функция sys.exc_info() возвращает кортеж, состоящий из трех значений:

  • type — тип возникшего исключения. Это подкласс BaseException.
  • value — это экземпляр типа исключения.
  • Traceback — это объект, который инкапсулирует стек вызовов в той точке, где изначально произошло исключение.

В следующем примере функция sys.exc_info() используется для проверки исключения, когда строка делится на число:

import sys

try:
    '20' / 2
except:
    exc_info = sys.exc_info()
    print(exc_info)

Выход:

(<class 'TypeError'>, TypeError("unsupported operand type(s) for /: 'str' and 'int'"), <traceback object at 0x000001F19F42E700>)

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

try:
    '20' / 2
except TypeError as e:
    print(e)

Выход:

unsupported operand type(s) for /: 'str' and 'int'
Похожие посты
Добавить комментарий

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