Содержание

Мир Python: исключения | Python для продвинутых

Зарегистрируйтесь для доступа к 15+ бесплатным курсам по программированию с тренажером

Введение

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

Исключительные ситуации или исключения (exceptions) – это ошибки, обнаруженные при исполнении. Например, к чему приведет попытка чтения несуществующего файла? Или если файл был случайно удален пока программа работала? Такие ситуации обрабатываются при помощи исключений.

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

Простейший пример исключения — деление на ноль:

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

В данном случае интерпретатор сообщил нам об исключении ZeroDivisionError – делении на ноль.

Traceback

В большой программе исключения часто возникают внутри. Чтобы упростить программисту понимание ошибки и причины такого поведения Python предлагает Traceback или в сленге – трэйс. Каждое исключение содержит краткую информацию, но при этом полную, информацию о месте появления ошибки. По трэйсу найти и исправить ошибку становится проще.

Рассмотрим такой пример:

Traceback (most recent call last):
  File "/home/username/Develop/test/app.py", line 862, in _handle
    return route.call(**args)
  File "/home/username/Develop/test/app.py", line 1729, in wrapper
    rv = callback(*a, **ka)
  File "/home/username/Develop/test/__init__.py", line 76, in wrapper
    body = callback(*args, **kwargs)
  File "/home/username/Develop/test/my_app.py", line 16, in index
    raise Exception('test exception')

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

Рассмотрим какие ещё встречаются комментарии к исключениям:

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

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

>>> int('qwerty')
Traceback (most recent call last):
  File "", line 1, in
    int('qwerty')
ValueError: invalid literal for int() with base 10: 'qwerty'

Приведение строчки к целому числу приводит к исключению ValueError.

В трэйсе этих двух примеров можно прочесть, что в таком-то файле на такой-то строчке есть ошибки.

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

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

Исключение, которое вы не увидите при выполнении кода – это BaseException – базовое исключение, от которого берут начало остальные.

В иерархии исключений две основные группы:

  • Системные исключения и ошибки
  • Обыкновенные исключения

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

К системным можно смело отнести:

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

Остальные исключения – это «обыкновенные». Спектр уже готовых исключений велик.

Для Python2 иерархию исключений можно представить так:

Список исключений покрывает большой объем ситуаций и ошибок программиста. Если предупреждения (warning) только просят обратить внимание, то ошибки уже могут остановить исполнение программы.

В Python3 появились новые исключения и иерархия стала такова:

В целом заметно, что при создании Python3 добавлен блок новых исключений. Но даже этих почти 70 исключений не хватает при написании программ на языке Python.

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

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

Начнем с обработки.

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

Давайте рассмотрим случай с делением на 0.

>>> a = 100
>>> b = 0
>>> c = a / b

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

try..except, например, так:

>>> try:
...     a = 100
...     b = 0
...     c = a / b
... except ZeroDivisionError as e:
...     print(e)
...
division by zero

Если исполнить этот код, то на консоль будет выведена строка «integer division or modulo by zero«. Казалось бы, что толком ничего это нам не дало, ошибка все также есть. Однако в блок except можно поместить обработку.

Например, мы условились, что значение переменной c в случае ошибки деления равно -1. Тогда модифицируем код:

>>> try:
...     a = 100
...     b = 0
...     c = a / b
... except ZeroDivisionError as e:
.
.. c = -1 >>> c -1

Перед тем как идти дальше, рассмотрим ещё одну возможность.

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

Используя исключения, можно вот так решить эту задачу:

try:
    filepath = 'test_file.txt'
    with open(filepath, 'r') as fio:
        result = fio.readlines()
    if not result:
        raise Exception("File is empty")
except IOError as e:
    result = []
except Exception as e:
    result = []
    print(e)

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

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

try:
    your_code
except (IOError, Exception) as e:
    print(e)

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

При работе с исключениями программист тратит большую часть времени на обработку, но при этом возникают ситуации, когда исключениями надо и бросать в других.

На сленге программистов «бросить исключение» означает написать код, который при исполнении будет инициировать исключительную ситуацию.

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

Чтобы бросить исключение необходимо воспользоваться raise

Пример:

raise IOError("текст исключения")

где IOError это класс исключения.

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

try:
    your_code
except Exception as e:
    raise

Собственные исключения

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

В минимальном исполнении необходимо наследоваться от какого-нибудь класса в иерархии исключений. Например так:

class MyException(Exception):
    pass

Тогда можно бросить своё исключение:

raise MyException(Exception)

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

Как правило, исключения это очень маленькие классы. Они должны выполняться максимально быстро.

Дополнение: Полная форма try..except

Форма try...except не полная, полной же является try..except..else..finally.

Применение полной конструкции может заметно упростить код, а также сделать его более безопасным.

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

Иными словами, finally выполняет блок инструкций в любом случае, было ли исключение, или нет. А инструкция else выполняется в том случае, если исключения не было.

В целом, использование полной формы таково:

try:
    исполяем какой-то код
except Exception as e:
    обработка исключения
else:
    код, который будет исполнен в случае, когда не возникает исключения
finally:
    код, который гарантированно будет исполнен последним (всегда исполняется)

Выводы

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

  • Что такое исключение
  • Какие типы исключений присутствуют в языке
  • Как обрабатывать исключения
  • Как вызвать исключения
  • Как создавать собственные исключения

Остались вопросы? Задайте их в разделе «Обсуждение»

Вам ответят команда поддержки Хекслета или другие студенты.

azureml.interpret.common.exceptions module — Azure Machine Learning Python

Обратная связь

Twitter LinkedIn Facebook Адрес электронной почты

  • Ссылка

Определяет пользовательские исключения, создаваемые пакетом azureml-interpret.

Классы

ConflictingRawTransformationsException

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

DimensionMismatchException

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

DirectoryExistsException

Исключение, указывающее, что такой каталог уже существует.

ExplanationNotFoundException

Исключение, указывающее, что не удалось найти объяснение.

InitDatasetMissingException

Исключение, указывающее, что набор данных инициализации отсутствует.

MissingEvalDataException

Исключение, указывающее, что набор данных для оценки не был передан в сценарий.

MissingExplainException

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

MissingExplanationTypesException

Исключение, указывающее, что типы объяснений не были переданы.

MissingPackageException

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

MissingRawTransformationsException

Исключение, указывающее, что сопоставление необработанных признаков не было передано в сценарий.

NoExperimentNameOrIdException

Исключение, указывающее, что у эксперимента выполнения нет свойств идентификатора или имени.

OptionalDependencyMissingException

Исключение, указывающее, что отсутствует необязательная зависимость.

SamplesExceededException

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

ScenarioNotSupportedException

Исключение, указывающее, что некоторый сценарий не поддерживается.

SerializationException

Исключение, связанное с недопустимыми сериализованными данными.

UnsupportedModelException

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

Обратная связь

Отправить и просмотреть отзыв по

Эта страница

Просмотреть все отзывы по странице

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'
Завершение программы

НазадСодержаниеВперед

Exceptions Python

Содержание
Введение
Пример с базовым Exception
Два исключения
except Error as e:: Печать текста ошибки
else
finally
raise
Пример 2
Пример 3
Исключения, которые не нужно обрабатывать
Список исключений
Разбор примеров: IndexError, ValueError, KeyError
Похожие статьи

Введение

Если в коде есть ошибка, которую видит интерпретатор поднимается исключение, создается так называемый Exception Object, выполнение останавливается, в терминале показывается Traceback.

В английском языке используется словосочетание Raise Exception

Исключение, которое не было предусмотрено разработчиком называется необработанным (Unhandled Exception)

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

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

Исключение, которое предусмотрено в коде называется обработанным (Handled)

Блок try except имеет следующий синтаксис

try: pass except Exception: pass else: pass finally: pass

В этой статье я создал файл try_except.py куда копирую код из примеров.

Пример

Попробуем открыть несуществующий файл и воспользоваться базовым Exception

try: f = open(‘missing. txt’) except Exception: print(‘ERR: File not found’)

python try_except.py

ERR: No missing.txt file found

Ошибка поймана, видно наше сообщение а не Traceback

Проверим, что когда файл существует всё хорошо

try: f = open(‘existing.txt’) except Exception: print(‘ERR: File not found’)

python try_except.py

Пустота означает успех

Два исключения

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

try: f = open(‘existing.txt’) x = bad_value except Exception: print(‘ERR: File not found’)

python try_except.py

ERR: File not found

Файл открылся, но так как в следующей строке ошибка — в терминале появилось вводящее в заблуждение сообщение. Проблема не в том, что «File not found» а в том, что bad_value нигде не определёно.

Избежать сбивающих с толку сообщений можно указав тип ожидаемой ошибки. В данном примере это FileNotFoundError

try: # expected exception f = open(‘existing.txt’) # unexpected exception should result in Traceback x = bad_value except FileNotFoundError: print(‘ERR: File not found’)

python try_except.py

Traceback (most recent call last): File «/home/andrei/python/try_except2.py», line 5, in <module> x = bad_value NameError: name ‘bad_value’ is not defined

Вторая ошибка не поймана поэтому показан Traceback

Поймать обе ошибки можно добавив второй Exception

try: # expected exception should be caught by FileNotFoundError f = open(‘missing.txt’) # unexpected exception should be caught by Exception x = bad_value except FileNotFoundError: print(‘ERR: File not found’) except Exception: print(‘ERR: Something unexpected went wrong’)

python try_except. py

ERR: File not found
ERR: Something unexpected went wrong

Печать текста ошибки

Вместо своего текста можно выводить текст ошибки. Попробуем с существующим файлом — должна быть одна пойманная ошибка.

try: # expected exception should be caught by FileNotFoundError f = open(‘existing.txt’) # unexpected exception should be caught by Exception x = bad_value except FileNotFoundError as e: print(e) except Exception as e: print(e)

python try_except.py

name ‘bad_value’ is not defined

Теперь попытаемся открыть несуществующий файл — должно быть две пойманные ошибки.

try: # expected exception should be caught by FileNotFoundError f = open(‘missing.txt’) # unexpected exception should be caught by Exception x = bad_value except FileNotFoundError as e: print(e) except Exception as e: print(e)

python try_except. py

name ‘bad_value’ is not defined
[Errno 2] No such file or directory: ‘missing.txt’

else

Блок else будет выполнен если исключений не будет поймано.

Попробуем открыть существующий файл existing.txt в котором есть строка www.heihei.ru

try: f = open(‘existing.txt’) except FileNotFoundError as e: print(e) except Exception as e: print(e) else: print(f.read()) f.close()

python try_except.py

www.heihei.ru

Если попробовать открыть несуществующий файл missing.txt то исключение обрабатывается, а код из блока else не выполняется.

[Errno 2] No such file or directory: ‘missing.txt’

finally

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

try: f = open(‘existing. txt’) except FileNotFoundError as e: print(e) except Exception as e: print(e) else: print(f.read()) f.close() finally: print(«Finally!»)

www.heihei.ru Finally!

А если попытаться открыть несуществующий missing.txt

[Errno 2] No such file or directory: ‘missing.txt’ Finally!

Когда нужно применять finally:

Рассмотрим скрипт, который вносит какие-то изменения в систему. Затем он пытается что-то сделать. В конце возвращает систему в исходное состояние.

Если ошибка случится в середине скрипта — он уже не сможет вернуть систему в исходное состояние.

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

import os def make_at(path, dir_name): original_path = os.getcwd() os.chdir(path) os.mkdir(dir_name) os.chdir(original_path)

Этот скрипт не вернётся в исходную директорию при ошибке в os. mkdir(dir_name)

А у скрипта ниже такой проблемы нет

def make_at(path, dir_name): original_path = os.getcwd() os.chdir(path) try: os.mkdir(dir_name) finally: os.chdir(original_path)

Не лишнима будет добавить обработку и вывод исключения

import os import sys def make_at(path, dir_name): original_path = os.getcwd() os.chdir(path) try: os.mkdir(dir_name) except OSError as e: print(e, file=sys.stderr) raise finally: os.chdir(original_path)

По умолчанию print() выводит в sys.stdout, но в случае ислючений логичнее выводить в sys.stderr

raise

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

try: f = open(‘outdated.txt’) if f.name == ‘outdated.txt’: raise Exception except FileNotFoundError as e: print(e) except Exception as e: print(‘File is outdated!’) else: print(f. read()) f.close() finally: print(«Finally!»)

python try_except.py

File is outdated! Finally!

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

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

Пример 2

Рассмотрим функцию, которая принимает числа прописью и возвращает цифрами

DIGIT_MAP = { ‘zero’: ‘0’, ‘one’: ‘1’, ‘two’: ‘2’, ‘three’: ‘3’, ‘four’: ‘4’, ‘five’: ‘5’, ‘six’: ‘6’, ‘seven’: ‘7’, ‘eight’: ‘8’, ‘nine’: ‘9’, } def convert(s): number = » for token in s: number += DIGIT_MAP[token] x = int(number) return x

python

>>> from exc1 import convert >>> convert(«one three three seven».split()) 1337

Теперь передадим аргумент, который не предусмотрен в словаре

>>> convert(«something unseen». split()) Traceback (most recent call last): File «<stdin>», line 1, in <module> File «/home/andrei/python/exc1.py», line 17, in convert number &plu= DIGIT_MAP[token] KeyError: ‘something’

KeyError — это тип Exception объекта. Полный список можно изучить в конце статьи.

Исключение прошло следующий путь:

REPL → convert() → DIGIT_MAP(«something») → KeyError

Обработать это исключение можно внеся изменения в функцию convert

convert(s): try: number = » for token in s: number += DIGIT_MAP[token] x = int(number) print(«Conversion succeeded! x = «, x) except KeyError: print(«Conversion failed!») x = -1 return x

>>> from exc1 import convert >>> convert(«one nine six one».split()) Conversion succeeded! x = 1961 1961 >>> convert(«something unseen».split()) Conversion failed! -1

Эта обработка не спасает если передать int вместо итерируемого объекта

>>> convert(2022) Traceback (most recent call last): File «<stdin>», line 1, in <module> File «/home/andrei/python/exc1. py», line 17, in convert for token in s: TypeError: ‘int’ object is not iterable

Нужно добавить обработку TypeError

… except KeyError: print(«Conversion failed!») x = -1 except TypeError: print(«Conversion failed!») x = -1 return x

>>> from exc1 import convert >>> convert(«2022».split()) Conversion failed! -1

Избавимся от повторов, удалив принты, объединив два исключения в кортеж и вынесем присваивание значения x из try блока.

Также добавим докстринг с описанием функции.

def convert(s): «»»Convert a string to an integer.»»» x = -1 try: number = » for token in s: number += DIGIT_MAP[token] x = int(number) except (KeyError, TypeError): pass return x

>>> from exc4 import convert >>> convert(«one nine six one».split()) 1961 >>> convert(«bad nine six one». split()) -1 >>> convert(2022) -1

Ошибки обрабатываются, но без принтов, процесс не очень информативен.

Грамотно показать текст сообщений об ошибках можно импортировав sys и изменив функцию

import sys DIGIT_MAP = { ‘zero’: ‘0’, ‘one’: ‘1’, ‘two’: ‘2’, ‘three’: ‘3’, ‘four’: ‘4’, ‘five’: ‘5’, ‘six’: ‘6’, ‘seven’: ‘7’, ‘eight’: ‘8’, ‘nine’: ‘9’, } def convert(s): «»»Convert a string to an integer.»»» try: number = » for token in s: number += DIGIT_MAP[token] return(int(number)) except (KeyError, TypeError) as e: print(f»Conversion error: {e!r}», file=sys.stderr) return -1

>>> from exc1 import convert >>> convert(2022) Conversion error: TypeError(«‘int’ object is not iterable») -1 >>> convert(«one nine six one».split()) 1961 >>> convert(«bad nine six one».split()) Conversion error: KeyError(‘bad’)

Ошибки обрабатываются и их текст виден в терминале.

С помощью !r выводится repr() ошибки

raise вместо кода ошибки

В предыдущем примере мы полагались на возвращение числа -1 в качестве кода ошибки.

Добавим к коду примера функцию string_log() и поработаем с ней

def string_log(s): v = convert(s) return log(v)

>>> from exc1 import string_log >>> string_log(«one two eight».split()) 4.852030263919617 >>> string_log(«bad one two».split()) Conversion error: KeyError(‘bad’) Traceback (most recent call last): File «<stdin>», line 1, in <module> File «/home/andrei/exc1.py», line 32, in string_log return log(v) ValueError: math domain error

convert() вернул -1 а string_log попробовал его обработать и не смог.

Можно заменить return -1 на raise. Это считается более правильным подходом в Python

def convert(s): «»»Convert a string to an integer. «»» try: number = » for token in s: number += DIGIT_MAP[token] return(int(number)) except (KeyError, TypeError) as e: print(f»Conversion error: {e!r}», file=sys.stderr) raise

>>> from exc7 import string_log >>> string_log(«one zero».split()) 2.302585092994046 >>> string_log(«bad one two».split()) Conversion error: KeyError(‘bad’) Traceback (most recent call last): File «<stdin>», line 1, in <module> File «/home/andrei/exc7.py», line 31, in string_log v = convert(s) File «/home/andrei/exc7.py», line 23, in convert number += DIGIT_MAP[token] KeyError: ‘bad’

Пример 3

Рассмотрим алгоритм по поиску квадратного корня

def sqrt(x): «»»Compute square roots using the method of Heron of Alexandria. Args: x: The number for which the square root is to be computed. Returns: The square root of x. «»» guess = x i = 0 while guess * guess != x and i < 20: guess = (guess + x / guess) / 2.0 i += 1 return guess def main(): print(sqrt(9)) print(sqrt(2)) if __name__ == ‘__main__’: main()

python sqrt_ex.py

3.0 1.414213562373095

При попытке вычислить корень от -1 получим ошибку

def main(): print(sqrt(9)) print(sqrt(2)) print(sqrt(-1))

python sqrt_ex.py

3.0 1.414213562373095 Traceback (most recent call last): File «/home/andrei/sqrt_ex.py», line 26, in <module> main() File «/home/andrei/sqrt_ex.py», line 23, in main print(sqrt(-1)) File «/home/andrei/sqrt_ex.py», line 16, in sqrt guess = (guess &plus; x / guess) / 2.0 ZeroDivisionError: float division by zero

В строке

guess = (guess + x / guess) / 2.0

Происходит деление на ноль

Обработать можно следующим образом:

def main(): try: print(sqrt(9)) print(sqrt(2)) print(sqrt(-1)) except ZeroDivisionError: print(«Cannot compute square root » «of a negative number. «) print(«Program execution continues » «normally here.»)

Обратите внимание на то, что в try помещены все вызовы функции

python sqrt_ex.py

3.0 1.414213562373095 Cannot compute square root of a negative number. Program execution continues normally here.

Если пытаться делить на ноль несколько раз — поднимется одно исключение и всё что находится в блоке try после выполняться не будет

def main(): try: print(sqrt(9)) print(sqrt(-1)) print(sqrt(2)) print(sqrt(-1))

python sqrt_ex.py

3.0 Cannot compute square root of a negative number. Program execution continues normally here.

Каждую попытку вычислить корень из -1 придётся обрабатывать отдельно. Это кажется неудобным, но в этом и заключается смысл — каждое место где вы ждёте ислючение нужно помещать в свой try except блок.

Можно обработать исключение так:

try: while guess * guess != x and i < 20: guess = (guess + x / guess) / 2. 0 i += 1 except ZeroDivisionError: raise ValueError() return guess def main(): print(sqrt(9)) print(sqrt(-1))

python sqrt_ex.py

3.0 Traceback (most recent call last): File «/home/andrei/sqrt_ex3.py», line 17, in sqrt guess = (guess + x / guess) / 2.0 ZeroDivisionError: float division by zero During handling of the above exception, another exception occurred: Traceback (most recent call last): File «/home/andrei/sqrt_ex3.py», line 30, in <module> main() File «/home/andrei/sqrt_ex3.py», line 25, in main print(sqrt(-1)) File «/home/andrei/sqrt_ex3.py», line 20, in sqrt raise ValueError() ValueError

Гораздо логичнее поднимать исключение сразу при получении аргумента

def sqrt(x): «»»Compute square roots using the method of Heron of Alexandria. Args: x: The number for which the square root is to be computed. Returns: The square root of x. Raises: ValueError: If x is negative «»» if x < 0: raise ValueError( «Cannot compute square root of » f»negative number {x}») guess = x i = 0 while guess * guess != x and i < 20: guess = (guess + x / guess) / 2.0 i += 1 return guess def main(): print(sqrt(9)) print(sqrt(-1)) print(sqrt(2)) print(sqrt(-1)) if __name__ == ‘__main__’: main()

python sqrt_ex.py

3.0 Traceback (most recent call last): File «/home/avorotyn/python/lessons/pluralsight/core_python_getting_started/chapter8/sqrt_ex4.py», line 35, in <module> main() File «/home/avorotyn/python/lessons/pluralsight/core_python_getting_started/chapter8/sqrt_ex4.py», line 30, in main print(sqrt(-1)) File «/home/avorotyn/python/lessons/pluralsight/core_python_getting_started/chapter8/sqrt_ex4.py», line 17, in sqrt raise ValueError( ValueError: Cannot compute square root of negative number -1

Пока получилось не очень — виден Traceback

Убрать Traceback можно добавив обработку ValueError в вызов функций

import sys def sqrt(x): «»»Compute square roots using the method of Heron of Alexandria. Args: x: The number for which the square root is to be computed. Returns: The square root of x. Raises: ValueError: If x is negative «»» if x < 0: raise ValueError( «Cannot compute square root of » f»negative number {x}») guess = x i = 0 while guess * guess != x and i < 20: guess = (guess + x / guess) / 2.0 i += 1 return guess def main(): try: print(sqrt(9)) print(sqrt(2)) print(sqrt(-1)) print(«This is never printed») except ValueError as e: print(e, file=sys.stderr) print(«Program execution continues normally here.») if __name__ == ‘__main__’: main()

python sqrt_ex.py

3.0 1.414213562373095 Cannot compute square root of negative number -1 Program execution continues normally here.

Исключения, которые не нужно обрабатывать

IndentationError, SyntaxError, NameError нужно исправлять в коде а не пытаться обработать.

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

Список исключений

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

Существуют следующие типы объектов Exception

BaseException &plus;— SystemExit &plus;— KeyboardInterrupt &plus;— GeneratorExit &plus;— Exception &plus;— StopIteration &plus;— StopAsyncIteration &plus;— ArithmeticError | &plus;— FloatingPointError | &plus;— OverflowError | &plus;— ZeroDivisionError &plus;— AssertionError &plus;— AttributeError &plus;— BufferError &plus;— EOFError &plus;— ImportError | &plus;— ModuleNotFoundError &plus;— LookupError | &plus;— IndexError | &plus;— KeyError &plus;— MemoryError &plus;— NameError | &plus;— UnboundLocalError &plus;— OSError | &plus;— BlockingIOError | &plus;— ChildProcessError | &plus;— ConnectionError | | &plus;— BrokenPipeError | | &plus;— ConnectionAbortedError | | &plus;— ConnectionRefusedError | | &plus;— ConnectionResetError | &plus;— FileExistsError | &plus;— FileNotFoundError | &plus;— InterruptedError | &plus;— IsADirectoryError | &plus;— NotADirectoryError | &plus;— PermissionError | &plus;— ProcessLookupError | &plus;— TimeoutError &plus;— ReferenceError &plus;— RuntimeError | &plus;— NotImplementedError | &plus;— RecursionError &plus;— SyntaxError | &plus;— IndentationError | &plus;— TabError &plus;— SystemError &plus;— TypeError &plus;— ValueError | &plus;— UnicodeError | &plus;— UnicodeDecodeError | &plus;— UnicodeEncodeError | &plus;— UnicodeTranslateError &plus;— Warning &plus;— DeprecationWarning &plus;— PendingDeprecationWarning &plus;— RuntimeWarning &plus;— SyntaxWarning &plus;— UserWarning &plus;— FutureWarning &plus;— ImportWarning &plus;— UnicodeWarning &plus;— BytesWarning &plus;— EncodingWarning &plus;— ResourceWarning

IndexError

Объекты, которые поддерживают протокол Sequence должны поднимать исключение IndexError при использовании несуществующего индекса.

IndexError как и KeyError относится к ошибкам поиска LookupError

Пример

>>> a = [0, 1, 2] >>> a[3]

Traceback (most recent call last): File «<stdin>», line 1, in <module> IndexError: list index out of range

ValueError

ValueError поднимается когда объект правильного типа, но содержит неправильное значение

>>> int(«text»)

Traceback (most recent call last): File «<stdin>», line 1, in <module> ValueError: invalid literal for int() with base 10: ‘text’

KeyError

KeyError поднимается когда поиск по ключам не даёт результата

>>> sites = dict(urn=1, heihei=2, eth2=3) >>> sites[«topbicycle»]

Traceback (most recent call last): File «<stdin>», line 1, in <module> KeyError: ‘topbicycle’

Похожие статьи
Python
Интерактивный режим
str: строки
\: перенос строки
Списки []
if, elif, else
Циклы
Функции
Пакеты
*args **kwargs
ООП
enum
Опеределить тип переменной Python
Тестирование с помощью Python
Работа с REST API на Python
Файлы: записать, прочитать, дописать, контекстный менеджер…
Скачать файл по сети
SQLite3: работа с БД
datetime: Дата и время в Python
json. dumps
Selenium &plus; Python
Сложности при работе с Python
DJANGO
Flask
Скрипт для ZPL принтера
socket :Python Sockets
Виртуальное окружение
subprocess: выполнение bash команд из Python
multiprocessing: несколько процессов одновременно
psutil: cистемные ресурсы
sys.argv: аргументы командной строки
PyCharm: IDE
pydantic: валидация данных
paramiko: SSH из Python
enumerate
logging: запись в лог
Обучение программированию на Python

Применение exception при накате Python-скрипта на Huawei / Хабр

Обычно мы можем встретить три проблемы при попытке запустить Python-скрипт на сети Huawei (впрочем, и на любой другой): это отсутствие L3 связности с устройством, это неверные имя пользователя или пароль, и это SSH-неполадки. Можно заметить, что любая из этих проблем остановит накат скрипта и сгенерирует один и тот же лог, большая часть из которого сложна для восприятия. В этой статье я постарался рассказать о небольшом улучшении предыдущего кода, которое сообщит о конкретной ошибке на устройстве, и продолжит накат скрипта дальше.

Запуск кода можно посмотреть на видео демонстрации.

Вывод лога ошибки без применения конструкции try — except — continue

Я буду использовать Python конструкцию try — except — continue. try позволяет протестировать блок кода на ошибки. except (exception или исключения) — это тип данных Python, который позволяет сообщить об ошибке. Большинство исключений уже описаны и встроены в Python, нужно лишь найти подходящий. 

Я также буду использовать оператор continue, чтобы накат скрипта продолжился несмотря на возникновение ошибки. А функция print() выведет заданное сообщение, если сработает то или иное исключение (except). Иными словами, если не удастся подключиться к устройству из списка устройств, то скрипт выведет короткое сообщение почему именно не удалось подключиться, и попытается подключиться к следующему устройству и так далее. Если ошибки не возникает, то код except пропускается. Еще раз подчеркну, что возникновение ошибки без конструкции try — except — continue, во-первых, сразу останавливает накат скрипта, то есть попытки подключения к другим устройствам из списка не происходит, а во-вторых, сгенерированный лог сообщения является длинным и беcсодержательным.

Итак, Python имеет встроенные исключения (except), которые описывают конкретные ошибки. Например:

Ошибка аутентификации — AuthenticationException

Ошибка недоступности — NetMikoTimeoutException

Ошибка SSH — SSHException

Блок кода except срабатывает только, если происходит ошибка. В этот блок входит функция print() и оператор continue. Например, если указать неверный пароль, то на экран будет выведено сообщение “Неверные данные аутентификации: ip-адрес устройства”. Если ни одна из ошибок не случится, то все три блока кода except будут пропущены, и отработает только главное задание скрипта — send_config_set (последняя строчка кода на примере выше).

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

from netmiko.ssh_exception import NetMikoTimeoutException
from paramiko.ssh_exception import SSHException
from netmiko.ssh_exception import AuthenticationException

Весь код приведу в конце статьи. 

Теперь тест в eNSP. В топологии восемь CloudEngine Huawei коммутатор. Из них я включу только три, остальные пять останутся недоступными (при попытке подключиться к ним скрипт должен вывести сообщение “Нет ответа от устройства: ip-адрес”). Первый коммутатор оставлю без ошибок, то есть на нем должно отработать задание автоматизации (накат конфигурации), на втором изменю пароль, а на третьем отключу SSH.

Топология eNSP для тестирования отработки ошибок

Изменяю пароль на CE2:

<CE_2>sys

Enter system view, return user view with return command.

[~CE_2]aaa

[~CE_2-aaa]local-user vasyo1 password irreversible-cipher @ghjcnjnF3589866

[*CE_2-aaa]commit

Отключаю SSH на VTY линиях на CE_3:

<CE_3>sys

Enter system view, return user view with return command.

[~CE_3]user-interface vty 0 4

[~CE_3-ui-vty0-4]protocol inbound telnet

[*CE_3-ui-vty0-4]commit

Теперь запущу скрипт:

Применение exception при накате Python-скрипта на Huawei

Первые строчки после Password — это содержание файлов в формате JSON, а именно файла, содержащего команды конфигурации, и файла, содержащего список IP-адресов устройств. Далее в первом красном прямоугольнике успешный накат конфигурации, во втором красном прямоугольнике сообщение о неверно введеных данных аутентификации (где я поменял пароль), и третий прямоугольник сообщает о недоступности SSH (где я разрешил использовать только telnet). Остальные пять коммутаторов: нет ответа от устройства и их IP-адреса (которые я и не включал).

Можно говорить об успешном применении конструкции try — except — continue.

Может посмотреть видео демонстарию наката, исходный код и его описание в статье: Мой друг Netmiko. Часть 2: Три улучшения Python-скрипта.

Полный код:

from getpass import getpass
from netmiko import ConnectHandler
from netmiko.ssh_exception import NetMikoTimeoutException
from paramiko.ssh_exception import SSHException
from netmiko.ssh_exception import AuthenticationException
username = input('Введите имя пользователя SSH: ')
password = getpass()
with open('switch_file_config') as f:
    config_lines = f.read().splitlines()
print (config_lines)
with open('myswitches') as f:
    ip_lines = f.read().splitlines()
print (ip_lines)
for device in ip_lines:
    ip_address_of_device = device
    CE = {
        'device_type': 'huawei',
        'ip':   ip_address_of_device,
        'username': username,
        'password': password
    }
    try:
        ssh_connect = ConnectHandler(**CE)
    except (AuthenticationException):
        print ('Неверные данные аутентификации: ' + ip_address_of_device)
        continue
    except (NetMikoTimeoutException):
        print ('Нет ответа от устройства: ' + ip_address_of_device)
        continue
    except (SSHException):
        print ('SSH недоступен.  Проверьте включен ли SSH? ' + ip_address_of_device)
        continue
    output = ssh_connect.send_config_set(config_lines)
    print(f"\n\n-------------- CE_{CE['ip']} --------------")
    print(output)
    print("-------------------- End -------------------")

Литература:

https://stackoverflow.com/questions/5563089/raw-input-function-in-python

https://pynet.twb-tech.com/blog/automation/netmiko.html

https://pyneng.readthedocs.io/en/latest/book/18_ssh_telnet/netmiko.html

https://github.com/ktbyers/netmiko

https://github.com/ktbyers/netmiko/blob/master/netmiko/ssh_dispatcher.py

Udemy.com — Python Network Programming for Network Engineers (Python 3) (David Bombal)

python exceptions — Конспекты (2022.09)

raise RuntimeError(u'Ошибка какая то')
class MyException(Exception): pass
assert False, u'Данная строка возбудит исключение AssertionError'

AttributeError()

class AttributeError

Возбуждается при обращении к несуществующему атрибуту

Наследник StandardError

ArithmeticError()

class ArithmeticError

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

Наследник StandardError

AssertionError()

class AssertionError

Возбуждается инструкциями assert

Наследник StandardError

BaseException()

class BaseException

Базовый класс всех исключений

EnvironmentError()

class EnvironmentError

Ошибка, обусловленная внешними причинами

Наследник StandardError

EOFError()

class EOFError

Возбуждается по достижении конца файла

Наследник StandardError

Exception()

class Exception

Базовый класс для всех исключений, не связанных с завершением программы

Наследник BaseException

FloatingPointError()

class FloatingPointError

Ошибка в инструкции import

Наследник ArithmeticError

GeneratorExit()

class GeneratorExit

Возбуждается методом . close() генераторов

Наследник BaseException

ImportError()

class ImportError

Ошибка в инструкции import

Наследник SyntaxError

IndentationError()

class IndentationError

Ошибка оформления отступов

Наследник SyntaxError

IndexError()

class IndexError

Ошибка обращения по индексу за пределами последовательности.

Наследник LookupError

IOError()

class IOError

Ошибка ввода-вывода при работе с файлами

Наследник EnvironmentError

KeyError()

class KeyError

Ошибка обращения к несуществующему ключу словаря

Наследник LookupError

KeyboardInterrupt()

class KeyboardInterrupt

Возбуждается нажатием клавишей прерывания (обычно Ctrl-C)

Наследник BaseException

LookupError()

class LookupError

Ошибка обращения по индексу или ключу

Наследник Exception

MemoryError()

class MemoryError

Нехватка памяти

Наследник Exception

NameError()

class NameError

Не удалось отыскать локальное или глобальное имя

Наследник Exception

NotImplementedError()

class NotImplementedError

Обращение к нереализованному методу или функции

Наследник Exception

OSError()

class OSError

Ошибка операционной системы

Наследник EnvironmentError

ReferenceError()

class ReferenceError

Ошибка обращения к объекту, который уже был уничтожен

Наследник Exception

RuntimeError()

class RuntimeError

Универсальное исключение

Наследник Exception

StandardError()

class StandardError

Базовый класс для всех встроенных исключений (только в Python 2).

В Python 3 – базовый класс всех исключений, наследующих класс Exception

Наследник Exception

StopIteration()

class StopIteration

Возбуждается для прекращения итераций

Наследник Exception

SyntaxError()

class SyntaxError

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

Наследник Exception

SystemError()

class SystemError

Нефатальная системная ошибка в интерпретаторе

Наследник Exception

SystemExit()

class SystemExit

Завершение программы

Наследник BaseException

TabError()

class TabError

Непоследовательное использование символа табуляции (генерируется при запуске интерпретатора с ключом –tt)

Наследник IndentationError

TypeError()

class TypeError

Попытка выполнить операцию над аргументом недопустимого типа

Наследник Exception

UnboundLocalError()

class UnboundLocalError

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

Наследник Exception

UnicodeError()

class UnicodeError

Ошибка при работе с символами Юникода

Наследник ValueError

UnicodeDecodeError()

class UnicodeDecodeError

Ошибка декодирования символов Юникода

Наследник ValueError

UnicodeEncodeError()

class UnicodeEncodeError

Ошибка кодирования символов Юникода

Наследник ValueError

UnicodeTranslateError()

class UnicodeTranslateError

Ошибка трансляции символов Юникода

Наследник ValueError

ValueError()

class ValueError

Недопустимый тип

Наследник Exception

ZeroDivisionError()

class ZeroDivisionError

Деление или деления по модулю на ноль

Наследник ArithmeticError

Введение — Real Python