Мир 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
Если исполнить этот код, то на консоль будет выведена строка «
Например, мы условились, что значение переменной 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: код, который гарантированно будет исполнен последним (всегда исполняется)
Выводы
В уроке рассмотрены вопросы связанные с исключениями:
- Что такое исключение
- Какие типы исключений присутствуют в языке
- Как обрабатывать исключения
- Как вызвать исключения
- Как создавать собственные исключения
Остались вопросы? Задайте их в разделе «Обсуждение»
Вам ответят команда поддержки Хекслета или другие студенты.
Что такое исключения в программировании
Большинство наших проектов устроены так: когда во время работы программы возникает какая-то ошибка, то программа аварийно завершается. Иногда при этом она выдаёт сообщение об ошибке. Кажется, что это нормальная ситуация, но на самом деле большинство ошибок можно предусмотреть и научить программу правильно с ними работать. Для этого нам нужны обработчики ошибок.
Что такое обработчик ошибок
Чтобы программа знала, что делать, если возникла какая-то ошибка, используют обработчики исключительных ситуаций, или, проще говоря, обработчики исключений. Смысл такой:
- Мы заранее прикидываем, в каком месте и почему может возникнуть ошибка.
- Пишем в этом месте специальный код, который предупредит компьютер, что это плановая ошибка и что у нас уже есть решение, мол, всё под контролем.
- Компьютер применяет наше решение и переходит к следующей команде.
- Программа не падает, не завершается с ошибкой, а продолжает работать.
Такие обработчики есть не в каждом языке программирования, но большинство современных языков это умеют делать.
Пример программы без обработчика исключений
Допустим, у нас в программе на Python предусмотрено чтение данных из файла и есть такой код:
file = open("myfile2.txt")
Но если на диске этого файла не будет, то компьютер, когда дойдёт до этой строчки, выдаст ошибку:
Uncaught SyntaxError: missing ) after argument list — что это значит
Давайте нарисуем это в виде простой схемы:
Получается, что наша задача — предусмотреть вариант, что на диске не будет нужного файла, и придумать поведение программы в этом случае. Используем для этого обработчик исключений.
Программа с обработчиком исключений
Если мы знаем, что в каком-то месте возможна ошибка, то можем тогда предусмотреть этот сценарий и подстраховаться. Для этого используют обработчик и делают так:
- В том месте, где можно предусмотреть ошибку, делают специальный блок.
- В этом блоке запускают команду и смотрят, будет ошибка или нет.
- Если ошибки нет — программа работает дальше.
- Если возникла ошибка — выполнятся то, что написано в обработчике ошибок, а потом программа работает дальше.
В этой ситуации программа не зависнет и не вывалится с ошибкой, а сама сможет её обработать и делать дальше то, что нужно:
try: file = open("myfile2.txt") except FileNotFoundError: print("Файл не найден, создаю новый") file = open("myfile2.txt","a")
Команда try — это начало нашего обработчика исключений. Она говорит компьютеру: «Попробуй выполнить вот эту команду, а мы посмотрим, что произойдёт».
Except — это какую ошибку мы ожидаем здесь увидеть. В нашем случае мы хотим предусмотреть случай, что такого файла нет, поэтому пишем стандартную ошибку для такой ситуации.
👉 Сравните текст этой ошибки с тем, что нам выдал компьютер в предыдущем разделе.
В других языках конструкция обработчика исключений может выглядеть по-другому, но смысл тот же: говорим компьютеру, какую команду нужно выполнить и что делать, если появилась конкретная ошибка.
Когда что-то не предусмотрено — будет ошибка
Если программе в этом блоке встретится другая ошибка, не та, которую мы предусмотрели, то программа остановится и всё перестанет работать. Например, вот какие ошибки могут возникнуть с файлом:
- файл есть на диске, но к нему нет прав доступа;
- файл занят другой программой;
- сам диск повреждён и данные не читаются.
Во всех этих случаях программа сломается, потому что мы не предусмотрели эти ситуации:
Получается, всё нужно делать с обработкой исключений?
Нет, и вот почему:
- Обработка исключений занимает лишнее время, поэтому программа с ними работает медленнее, чем без них.
- Не всё можно предусмотреть. Если разработчик не знает, что здесь может быть ошибка, то и предусмотреть он это тоже не сможет.
- Конструкции с обработчиками делают код менее читаемым и понятным для человека. Ему нужно будет держать в голове точку начала обработки, понять, как обработка влияет на программу в целом, и выяснить, что будет с программой после работы обработчика ошибок.
Конечно, есть места в коде, которые лучше делать с обработкой ошибок: работа с файлами, сетевые запросы или получение внешних данных. Но запихивать исключения на каждую команду в программе точно не стоит.
Текст:
Михаил Полянин
Редактура:
Максим Ильяхов
Художник:
Даня Берковский
Корректор:
Ирина Михеева
Вёрстка:
Мария Дронова
Соцсети:
Олег Вешкурцев
Передовой опыт обработки исключений — передовой опыт
- Обновлено 15 февраля 2022 г.
- 4 Минуты на чтение
Распечатать
Поделиться
Темный
Свет
Обзор
Исключение — это непредвиденная аномалия, которая может возникнуть во время выполнения. Исключения обычно возникают, когда функция Designer Element не может работать должным образом. Типичный пример исключения возникает, когда шаг имеет неправильное сопоставление данных. Это означает, что если шаг ожидает входного значения Int32, неожиданное значение String прекратит выполнение функции шага, отобразив сообщение об исключении с информацией об ошибке. Эти исключения будут происходить автоматически без настройки.
Исключения также могут возникать после шагов в потоке. Это позволяет выполнять дополнительную настройку, если возникает ошибка, которую пользователь хочет обрабатывать по-другому во время выполнения. Эта практика используется для прогнозирования ошибок или инициирования настраиваемых ошибок для эффективного управления. Доступные инструменты обработки исключений действуют как сеть безопасности для приложения во время выполнения, чтобы надлежащим образом информировать пользователей о возникновении и записывать трассировки.
Для каждого шага в потоке можно включить путь к результату при исключении, который может привести к другим шагам, которые помогут с записью журналов или другой обработкой данных в случае возникновения исключения. 9Шаг 0034 Catch Exception можно использовать для той же цели, за исключением того, что этот шаг будет автоматически запускаться при первом обнаружении любого исключения в потоке. Эту форму обработки исключений не нужно настраивать для каждого шага, поскольку решения будут захватывать функциональные исключения в любом случае и записывать их в файлы журналов серверной части.
Дополнительные сведения о том, какие типы ошибок регистрируются по умолчанию и как можно изменить эти параметры, см. в разделе Параметры ведения журнала.
Исключение по умолчанию Пример
В приведенном ниже примере шаг Добавить был добавлен к потоку без указания входных значений. При запуске отладчика автоматически возникает исключение. Сведения об исключении (как показано в отладчике) указывают на то, что шаг не имеет значений для выполнения предполагаемой функции и что ошибка была доставлена.
Исключение Ошибки по умолчанию записываются в основной файл журнала. Файлы журналов находятся в папке C:\Program Files\Decisions\Decisions Services Manager\Logs на локальном ПК.Папка 0035.
Этап перехвата исключений
Шаг Перехват исключений отвечает за перехват исключений немедленно по мере их возникновения в потоке. На снимке экрана ниже показан поток с двумя шагами добавления, оба из которых, как ожидается, вызовут ошибку во время выполнения.
В примере слева поток останавливает отладчик на первом шаге добавления, выдающем ошибку исключения, затем сведения об ошибке отправляются на шаг перехвата исключения. Поскольку шаг был прерван во время выполнения, поток не продолжается после шага, вызвавшего ошибку. Путь шага перехвата исключения будет продолжаться, поскольку он был запущен, когда в потоке возникло исключение.
В примере справа шаги добавления достигаются одновременно с выполнением потока. Опять же, поток останавливается, так как ни одна из функций не может быть завершена, а сведения об ошибках обоих шагов принимаются на шаге Catch Exception, так как оба произошли одновременно.
Шаг перехвата исключения обычно ведет к другим шагам обработки исключений, а затем к отдельному шагу завершения. В приведенном ниже примере шаг журнала добавляется после шага перехвата исключения, чтобы имитировать один из наиболее часто используемых шагов обработки исключений. Процессы обработки исключений, состоящие из нескольких шагов, лучше всего подходят, когда они разделены на подпотоки, тогда на подпоток с процессом обработки исключений можно ссылаться в любом месте проекта.
Использование подпотоков для обработки исключений
Подпоток — это дочерний поток, на который ссылаются из родительского потока. Дополнительные сведения о подпотоках и пример того, как выглядит обработка исключений в подпотоке, см. в статье Использование подпотоков.
Когда отладчик выполняет поток, выходные данные шага перехвата исключения используются для сопоставления входных данных шага журнала. Шаг журнала настроен на получение сообщения об исключении, стека, полной трассировки и имени шага из шага перехвата исключения и записи их во внутренние файлы журнала.
Шаг перехвата исключения также можно наблюдать вне отладчика в Decisions Studio. В приведенном ниже GIF поток выполняется с использованием шага «Поймать исключение» в конструкторе потоков. Когда используется Catch Exception, поток продолжает работать, как и ожидалось, на внешнем интерфейсе, несмотря на ошибку, возникающую на этапе добавления (поскольку она была зарегистрирована с использованием обработки исключений на внутреннем уровне). Когда этапы обработки исключений удаляются из потока, окно Flow Run Error появляется сразу во время выполнения, в отличие от дискретного завершения потока и записи ошибок.
В более сложном варианте использования процесс обработки исключений может содержать шаги, которые регистрируют ошибку, предупреждают или отправляют задачу пользователю, оценивают данные об ошибке по правилам и многое другое. Из-за этого разделение Sub Flow становится отличным инструментом для поддержания этих процессов.
Выходной путь при исключении
В Flow Designer шаги имеют возможность включить выходной путь При исключении на вкладке Свойства шага. Этот выходной путь работает так же, как шаг перехвата исключения, за исключением того, что он специфичен для включенного шага.
Выберите шаг и перейдите к категории РЕЗУЛЬТАТЫ на панели свойств. Установите флажок для параметра Добавить результат для исключения . Когда флажок установлен, появится новый выходной путь для шага. Шаги обработки исключений могут следовать по этому пути результата, как и в приведенных выше примерах. Когда поток выполняется с использованием выходного пути On Exception, этот путь будет использоваться при достижении Exception Error во время выполнения.
Была ли эта статья полезной?
Обработка исключений для AWS SDK для Java 2.x
Понимание того, как и когда AWS SDK для Java 2.x создает исключения, важно для построения высококачественные приложения с помощью SDK. В следующих разделах описаны различные случаи исключений, создаваемых пакетом SDK, и как правильно их обрабатывать.
Почему непроверенные исключения?
AWS SDK для Java использует исключения времени выполнения (или непроверенные) вместо проверенных исключений для этих причины:
Как правило, проверенные исключения хорошо работают в небольших масштабах, но могут создавать проблемы при приложения растут и усложняются.
AwsServiceException (и подклассы)
AwsServiceException — наиболее распространенное исключение, с которым вы столкнетесь, когда
с помощью AWS SDK для Java. AwsServiceException
является подклассом
более общее исключение SdkServiceException. AwsServiceException
s представляют ошибку
ответ от службы AWS. Например, если вы попытаетесь завершить
Экземпляр Amazon EC2, который не существует, Amazon EC2 вернет ошибку
ответ, и все детали этого ответа об ошибке будут включены в Выдано AwsServiceException
.
Когда вы сталкиваетесь с AwsServiceException
, вы знаете, что ваш запрос был
успешно отправлено в сервис AWS, но не может быть успешно обработано. Это может быть
из-за ошибок в параметрах запроса или из-за проблем на сервисе
сторона.
AwsServiceException
предоставляет вам такую информацию, как:
Возвращенный код состояния HTTP
Возвращенный код ошибки AWS
Подробное сообщение об ошибке от службы в классе AwsErrorDetails
Идентификатор запроса AWS для неудачного запроса
В большинстве случаев для конкретного сервиса создается подкласс AwsServiceException
. позволяют разработчикам точно контролировать обработку случаев ошибок с помощью блоков catch. Ява
Справочник API SDK для AwsServiceException отображает большое число Авссервицецепцептион
подклассы. Используйте ссылки подкласса для детализации и просмотра детальных исключений, создаваемых
услуга.
Например, следующие ссылки на справочник SDK API показывают иерархии исключений для нескольких распространенных сервисов AWS. Список подклассов, показанный на каждой странице, показывает конкретные исключения, которые ваш код может поймать.
Амазон S3
ДинамоДБ
Amazon SQS
Чтобы узнать больше об исключении, проверьте errorCode
в объекте AwsErrorDetails. Вы можете использовать значение errorCode
для поиска
информация в сервис-гиде API. Например, если S3Exception
перехвачено и
значение AwsErrorDetails#errorCode()
равно InvalidRequest
, используйте
список кодов ошибок в Справочнике по API Amazon S3, чтобы увидеть более подробную информацию.