raise
Инструкция позволяет прервать штатный поток исполнения при помощи возбуждения исключения.
На заметку
Дополнительная информация доступна в статьях: Встроенные исключения и try except finally.
Если после инструкции отсутствует выражение (например, не указывается тип исключения), то повторно поднимается отловленное исключение. Если в данной области нет активного исключения (например, raise не находится внутри блока except ), возбуждается RuntimeError (до -py3.0 возбуждалось TypeError).
try:
# Допустим в функции поднимается FileNotFoundError.
do()
except OSError:
# Инструкция raise без выражения поднимет FileNotFoundError повторно.
raise
Если выражение присутствует, то результатом его вычисления должен являться либо экземпляр наследника BaseException, либо сам наследник, то есть тип. Во втором случае объект исключения будет сформирован путём инстанциирования типа без аргументов.
# Объект сформируется из класса автоматически.
raise MyException
# Формируем объект исключения вручную.
raise MyException('Моё исключение')
Объект трассировки
Объект трассировки обычно создаётся автоматически при возбуждении исключения и подвязывается к нему в атрибут __traceback__ (поддерживает запись). Вы можете в один приём создать исключение и подвязать к нему трассировку при помощи метода исключения with_traceback() — метод вернёт тот же объект исключения для которого вызван:
raise Exception('Возбуждено исключение').with_traceback(traceback_obj)
Цепочки исключений
Для формирования цепочек исключений используется дополнение from , после которого требуется указать ещё одно исключение (класс, либо объект). Это исключение будет подвязано к возбуждаемому в атрибут __cause__ (поддерживает запись). В результате, если возбуждаемое исключение не обработано, но на вывод будут отправлены оба исключения:
try:
print(1 / 0)
except Exception as exc:
# Наше второе исключение никто не поймает
# поэтому будет выведена цепочка
# из двух исключений.
raise RuntimeError('Явная цепочка исключений') from exc
Похожий механизм срабатывает автоматически, если исключение возбуждается внутри обработчика, либо блока finally — предыдущее исключение подвязывается в атрибут __context__ нового:
try:
print(1 / 0)
except:
raise RuntimeError('Неявная цепочка исключений')
На заметку
+py3.3 Автоматическое формирование цепочки можно подавить, указав None после from . В ходе данной операции задействуется атрибут __suppress_context__ .
Python 2
Если после инструкции присутствуют от одного до трёх выражений, то они вычисляются, чтобы получить три объекта.
При помощи первых двух из этих объектов определяется тип и значение исключения.
Если первый объект явится экземпляром. То типом исключения будет являться тип этого экземпляра, а в роли значения будет выступит сам экземпляр. Второй объект при этом должен являться None .
Если первый объект явится классом. То он и станет типом исключения. При этом для определения значения исключения будет использован второй объект.
Второй объект.
1. Если он явится экземпляром, то этот экземпляр и станет значением исключения.
2. Если второй объект явится кортежем, то он будет использован в качестве списка аргументов для инициализатора класса.
3. Если объект явится None , то в инициализатор будет передан пустой список аргументов.
Экземпляр, созданный в ходе вызова инициализатора будет являться значением исключения.
Если присутствует третий объект
То он должен являться объектом трассировки. Данный объект в делает местом, где произошло исключение, текущее место в коде.
Если объект не является ни объектом трассировки, ни None , возбуждается исключение TypeError.
Использование трёх выражений служит для более прозрачного повторного возбуждения исключения. В сочетании с sys.exc_info() это в некоторой степени похоже на то, что делает from в Python 3:
try:
do()
except:
exc_info = sys.exc_info()
raise exc_info[0], exc_info[1], exc_info[2]
Инструкция raise, принудительно поднимает исключение
Инструкция raise позволяет программисту принудительно вызвать указанное исключение. Например:
>>> raise NameError('HiThere') # Traceback (most recent call last): # File "", line 1, in # NameError: HiThere
В общем случае инструкция raise повторно вызывает последнее исключение, которое было активным в текущей области видимости. Если нужно определить, было ли вызвано исключение, но не обрабатывать его, более простая форма инструкции raise позволяет повторно вызвать исключение:
try: raise NameError('HiThere') except NameError: print('Исключение пролетело незаметно!') # Еще какие-то действия, например запись в журнал логов . # затем повторно вызываем `NameError` raise # Исключение пролетело незаметно! # Traceback (most recent call last): # File "", line 2, in # NameError: HiThere
Если в текущей области видимости нет активного исключения, то в месте, где указана инструкция raise , без указания , возникает исключение RuntimeError , указывающее на ошибку.
>>> raise # Traceback (most recent call last): # File "", line 1, in # RuntimeError: No active exception to reraise
В противном случае raise вычисляет первое выражение как объект исключения. Он должен быть подклассом BaseException , например Exception или один из его подклассов. Если передается класс исключения, он будет неявно создан путем вызова его конструктора без аргументов.
# сокращение для 'raise ValueError()' >>> raise ValueError # Traceback (most recent call last): # File "", line 1, in # ValueError
При возникновении исключения объект traceback обычно создается автоматически и присоединяется к нему в качестве атрибута __traceback__ . Следовательно можно создать исключение путем raise и установить в него свой собственный traceback за один шаг, используя метод BaseException.with_traceback() , например:
try: . except SomeException: # Получаем трассировку tb = sys.exception().__traceback__ # передаем трассировку raise AnyException(. ).with_traceback(tb)
Инструкция raise и цепочка исключений.
Если внутри раздела except (конструкции try/except ) появляется НЕперехваченное исключение (например с помощью raise ), то к нему будет привязано исключение, которое было перехвачено инструкцией except в качестве атрибута __cause__ , и оба будут выведены в сообщении об ошибке:
try: open("database.sqlite") except OSError: raise RuntimeError("не удается обработать ошибку") # Traceback (most recent call last): # File "", line 2, in # FileNotFoundError: [Errno 2] No such file or directory: 'database.sqlite' # During handling of the above exception, another exception occurred: # Traceback (most recent call last): # File "", line 4, in # RuntimeError: не удается обработать ошибку
Подобный механизм работает неявно, если исключение вызывается внутри обработчика исключений (внутри предложения try ) или внутри предложения finally , то предыдущее исключение присоединяется в качестве атрибута __context__ нового исключения:
Оператор raise допускает необязательное предложение from , которое используется для указания того, что одно исключение является прямым следствием другого:
def func(): raise ConnectionError try: func() except ConnectionError as exc: raise RuntimeError('Не удалось открыть базу данных') from exc # Traceback (most recent call last): # File "", line 2, in # File "", line 2, in func # ConnectionError # The above exception was the direct cause of the following exception: # Traceback (most recent call last): # File "", line 4, in # RuntimeError: Не удалось открыть базу данных
Цепочка исключений может быть явно подавлена/отключена путем указания значения None в предложении from :
try: a = 1 / 0 except Exception as exc: raise RuntimeError("Случилось что-то плохое") from None # Traceback (most recent call last): # File "", line 4, in # RuntimeError: Случилось что-то плохое
Пример вызова исключения, когда выполнение программы бессмысленно или не может продолжаться.
# например, поступили данные с клавиатуры s = 'apple' try: # пытаемся преобразовать данные num = int(s) except ValueError: raise ValueError("Строка не может быть преобразована в целое число") from None # Traceback (most recent call last): # File "", line 5, in # ValueError: Строка не может быть преобразована в целое число
- ОБЗОРНАЯ СТРАНИЦА РАЗДЕЛА
- Обработка/перехват исключений try/except
- Инструкция finally, очистка внешних ресурсов
- Тонкости работы конструкции try/except/else/finally
- Создание пользовательского класса исключения
- Обработка группы исключений, оператор except*
- Эффективная обработка исключений
- Инструкция raise, принудительный вызов исключений
- Отладочные утверждение assert
- Улучшения сообщений об ошибках 3.10
- Улучшения сообщений об ошибках 3.11
- Улучшения сообщений об ошибках 3.12
Инструкция raise и пользовательские исключения
Мы продолжаем тему исключений. Во всех наших предыдущих примерах исключение возникало в результате ошибочных ситуаций во время работы программы, например, деления на ноль:
print("Куда ты скачешь, гордый конь,") print("И где опустишь ты копыта?") print("О мощный властелин судьбы!") 1/0 print("Не так ли ты над самой бездной") print("На высоте, уздой железной") print("Россию поднял на дыбы?")
Но как эта операция деления формирует само исключение? Для этого в языке Python имеется конструкция (оператор)
которая и порождает указанные типы исключений. В самом простом варианте, мы можем вместо деления на ноль записать этот оператор и указать тип исключения ZeroDivisionError:
raise ZeroDivisionError("Деление на ноль")
Результат выполнения программы будет тем же – она остановится на конструкции raise. Только сообщение об ошибке теперь будет на русском языке – та строка, что мы указали при формировании объекта класса ZeroDivisionError. То есть, после оператора raise мы можем прописывать нужный нам класс исключения с собственными параметрами. Также можно просто указывать класс, не прописывая каких-либо параметров:
raise ZeroDivisionError
Здесь у нас также создается экземпляр, но без параметров. Раз это так, значит, можно заранее создать экземпляр класса:
e = ZeroDivisionError("Деление на ноль")
а, затем, сгенерировать это исключение:
raise e
Вообще, мы можем использовать любой класс в качестве исключения, унаследованного от базового класса:
Например, если просто указать строку после оператора raise:
raise "деление на ноль"
то интерпретатор Python как раз это нам и укажет:
TypeError: exceptions must derive from BaseException
То есть, после raise должен находиться экземпляр класса исключения, а не какой-то произвольный объект.
Когда нам может понадобиться оператор raise? И разве сам язык Python не может генерировать нужные исключения при возникновении ошибок? Часто именно так и происходит. Например, если мы будем делать некорректные операции, вроде:
1 + "2" [1, 2, 3][4]
то автоматически возникают ошибки заданного типа. Но прописать исключения на все случаи жизни невозможно. И если в качестве примера взять все тот же класс печати данных:

То, в частности, метод send_data() может генерировать свое исключение, если по каким-то причинам данные не были отправлены принтеру. В качестве демонстрации я приведу гипотетический класс PrintData для работы с принтером:
class PrintData: def print(self, data): self.send_data(data) print(f"печать: ") def send_data(self, data): if not self.send_to_print(data): raise Exception("принтер не отвечает") def send_to_print(self, data): return False
Как раз здесь мы генерируем исключение, если данные не могут быть отправлены принтеру. Затем, это исключение может быть обработано на любом уровне стека вызова. Например, если далее создать экземпляр этого класса и вызвать метод print():
p = PrintData() p.print("123")
То мы увидим сформированное нами исключение. Как вы понимаете, в язык Python не встроена по умолчанию возможность генерации исключения при взаимодействии с принтером. Это приходится делать уже самому программисту с помощью оператора raise. Вот для этого он и нужен.
Создание пользовательских исключений
В нашем гипотетическом классе PrintData исключение генерируется с помощью класса Exception. Почему именно он? Если мы посмотрим на иерархию классов исключений языка Python, то здесь во главе стоит базовый класс BaseException:

Остальные классы наследуются от него и имеют строгую специализацию, кроме, разве что, класса Exception, который является общим для большого разнообразия типов исключений в момент выполнения программы. Так почему же мы выбрали класс Exception, а не BaseException? Дело в том, что классы SystemExit, GeneratorExit и KeyboardInterrupt являются весьма специфичными и, обычно, они не используются при обработке собственных исключений. Поэтому, целесообразно выбирать именно класс Exception для формирования новых собственных классов исключений. Что мы сейчас и сделаем.
Итак, чтобы сформировать свой новый тип исключения, нужно прописать класс, который рекомендуется наследовать от класса Exception. В самом простом варианте достаточно просто описать иерархию:
class ExceptionPrintSendData(Exception): """Класс исключения при отправке данных принтеру"""
И далее в программе использовать этот новый класс:
def send_data(self, data): if not self.send_to_print(data): raise ExceptionPrintSendData("принтер не отвечает")
Соответственно, ниже в программе, мы можем обработать этот тип ошибки, просто указав имя нашего нового класса:
p = PrintData() try: p.print("123") except ExceptionPrintSendData: print("Ошибка печати")
Видите, как это здорово! Мы создали новый тип исключения, просто прописав новый класс. И благодаря этому можем отличить ошибку передачи данных принтеру от каких-либо других ошибок.
Разумеется, мы поймаем эту же ошибку, если укажем базовый класс Exception, но пропустим, если указать какой-либо другой независимый класс исключения, иерархически не связанный с нашим, например, ArithmeticError.
Кроме того, мы можем расширить функционал класса ExceptionPrintSendData. Давайте добавим в него конструктор. Он прописывается для произвольного числа аргументов:
class ExceptionPrintSendData(Exception): """Класс исключения при отправке данных принтеру""" def __init__(self, *args): self.message = args[0] if args else None
А также магически метод__str__ для представления ошибки в консоли:
def __str__(self): return f"Ошибка: "
Если теперь убрать блок try/except и вызвать метод print(), то увидим наш вариант отображения ошибки в консоли:
p = PrintData() p.print("123")
Это лишь пример расширения функционала класса исключения. В каждом конкретном случае программист может написать любую свою реализацию.
Наконец, пользовательские классы исключений дают возможность создавать свою иерархию исключений. В частности, в нашем примере, можно прописать общий класс исключений для принтера ExceptionPrint:
class ExceptionPrint(Exception): """Общий класс исключения принтера"""
А, затем, остальные, более конкретные типы наследовать от него:
class ExceptionPrintSendData(ExceptionPrint): """Класс исключения при отправке данных принтеру"""
В результате, в блоке except мы можем отлавливать как конкретные типы ошибок, так и общие, связанные с принтером:
p = PrintData() try: p.print("123") except ExceptionPrintSendData as e: print(e) except ExceptionPrint: print("Ошибка печати")
Такой подход дает гибкий механизм обработки собственных типов исключений, благодаря чему, программа становится более понятной и структурированной.
Видео по теме

Концепция ООП простыми словами

#1. Классы и объекты. Атрибуты классов и объектов

#2. Методы классов. Параметр self

#3. Инициализатор __init__ и финализатор __del__

#4. Магический метод __new__. Пример паттерна Singleton

#5. Методы класса (classmethod) и статические методы (staticmethod)

#6. Режимы доступа public, private, protected. Сеттеры и геттеры

#7. Магические методы __setattr__, __getattribute__, __getattr__ и __delattr__

#8. Паттерн Моносостояние

#9. Свойства property. Декоратор @property

#10. Пример использования объектов property

#11. Дескрипторы (data descriptor и non-data descriptor)

#12. Магический метод __call__. Функторы и классы-декораторы

#13. Магические методы __str__, __repr__, __len__, __abs__

#14 Магические методы __add__, __sub__, __mul__, __truediv__

#15. Методы сравнений __eq__, __ne__, __lt__, __gt__ и другие

#16. Магические методы __eq__ и __hash__

#17. Магический метод __bool__ определения правдивости объектов

#18. Магические методы __getitem__, __setitem__ и __delitem__

#19. Магические методы __iter__ и __next__

#20. Наследование в объектно-ориентированном программировании

#21. Функция issubclass(). Наследование от встроенных типов и от object

#22. Наследование. Функция super() и делегирование

#23. Наследование. Атрибуты private и protected

#24. Полиморфизм и абстрактные методы
#25. Множественное наследование

#26. Коллекция __slots__

#27. Как работает __slots__ с property и при наследовании

#28. Введение в обработку исключений. Блоки try / except

#29. Обработка исключений. Блоки finally и else

#30. Распространение исключений (propagation exceptions)

#31. Инструкция raise и пользовательские исключения

#32. Менеджеры контекстов. Оператор with

#33. Вложенные классы

#34. Метаклассы. Объект type

#35. Пользовательские метаклассы. Параметр metaclass

#36. Метаклассы в API ORM Django

#37. Введение в Python Data Classes (часть 1)

#38. Введение в Python Data Classes (часть 2)

#39. Python Data Classes при наследовании
© 2024 Частичное или полное копирование информации с данного сайта для распространения на других ресурсах, в том числе и бумажных, строго запрещено. Все тексты и изображения являются собственностью сайта
Исключения в Python. Операторы вызова исключений: raise и assert
Бывают ситуации, когда формально ошибки нет, но переменная принимает такое значение, при котором программа может дать результат, очень далёкий от ожидания. И тогда мы можем вызвать ошибку принудительно, с помощью оператора raise:
try: value = int(input()) if value % 2 != 0: raise ValueError('Variable must be even!') print('Congratulations! Variable is even!') except Exception as e: print(f': ')
В приведённом примере исключение будет вызвано в том случае, когда целое число не является чётным, то есть в случае выполнения условия if value % 2 != 0:
Для этого после оператора raise указывается класс исключения (в данном случае это ValueError), к которому будет отнесена соответствующая группа значений переменной value. А далее, в скобках, добавлен комментарий, поясняющий причину вызова исключения. Ниже приводятся результаты выполнения кода для значений 4 и 5:
>>> 5 : Variable must be even! 4 'Congratulations! Variable is even!'
Если появится другая ошибка, например, если с консоли будет введено значение aaa, то программа перейдёт на обработку этого исключения ещё до оператора raise. И, разумеется, выдаст совершенно другой код ошибки (точнее, выдаст другой комментарий ошибки к общему классу исключений ValueError):
>>> aaa : invalid literal for int() with base 10: 'aaa'
Оператор assert
Ещё одна возможность принудительно вызвать ошибку, в случае невыполнения указанного условия — с помощью оператора assert:
try: value = int(input()) assert value % 2 == 0, 'Variable must be even!' print('Congratulations! Variable is even!') except Exception as e: print(f': ')
Варианты выполнения кода для различных входных значений:
>>> 5 : 'Variable must be even! 4 'Congratulations! Variable is even!' aaa : invalid literal for int() with base 10: 'aaa'
Таким образом, как видим, оба оператора (raise и assert) очень похожи друг на друга.
- assert не требует отдельного блока if — условие проверки с этим оператором делается в одну строку;
- В случае assert не требуется указывать класс исключения — по умолчанию это всегда AssertionError