Что такое raise в python
Иногда возникает необходимость вручную сгенерировать то или иное исключение. Для этого применяется оператор raise . Например, сгенерируем исключение
try: number1 = int(input("Введите первое число: ")) number2 = int(input("Введите второе число: ")) if number2 == 0: raise Exception("Второе число не должно быть равно 0") print("Результат деления двух чисел:", number1/number2) except ValueError: print("Введены некорректные данные") except Exception as e: print(e) print("Завершение программы")
Оператору raise передается объект BaseException — в данном случае объект Exception. В конструктор этого типа можно ему передать сообщение, которое затем можно вывести пользователю. В итоге, если number2 будет равно 0, то сработает оператор raise, который сгенерирует исключение. В итоге управление программой перейдет к блоку except , который обрабатывает исключения типа Exception:
Введите первое число: 1 Введите второе число: 0 Второе число не должно быть равно 0 Завершение программы
Создание своих типов исключений
В языке Python мы не ограничены только встроенными типами исключений и можем, применяя наследование, при необходимости создавать свои типы исключений. Например, возьмем следующий класс Person:
class Person: def __init__(self, name, age): self.__name = name # устанавливаем имя self.__age = age # устанавливаем возраст def display_info(self): print(f"Имя: Возраст: ")
Здесь класс Person в конструкторе получает значения для имени и возраста и присваивает их приватным переменным name и age. Однако при создании объекта Person мы можем передать в конструктор некорректное с точки зрения логики значение — например, отрицательное число. Одним из способов решения данной ситуации представляет генерация исключения при передаче некорректных значений.
Итак, определим следующий код программы:
class PersonAgeException(Exception): def __init__(self, age, minage, maxage): self.age = age self.minage = minage self.maxage = maxage def __str__(self): return f"Недопустимое значение: . " \ f"Возраст должен быть в диапазоне от до " class Person: def __init__(self, name, age): self.__name = name # устанавливаем имя minage, maxage = 1, 110 if minage < age < maxage: # устанавливаем возраст, если передано корректное значение self.__age = age else: # иначе генерируем исключение raise PersonAgeException(age, minage, maxage) def display_info(self): print(f"Имя: Возраст: ") try: tom = Person("Tom", 37) tom.display_info() # Имя: Tom Возраст: 37 bob = Person("Bob", -23) bob.display_info() except PersonAgeException as e: print(e) # Недопустимое значение: -23. Возраст должен быть в диапазоне от 1 до 110
В начале здесь определен класс PersonAgeException, который наследуется от класса Exception. Как правило, собственные классы исключений наследуются от класса Exception. Класс PersonAgeException предназначен для исключений, связанных с возрастом пользователя.
В конструкторе PersonAgeException получаем три значения - собственное некорректное значение, которое послужило причиной исключения, а также минимальное и максимальное значения возраста.
class PersonAgeException(Exception): def __init__(self, age, minage, maxage): self.age = age self.minage = minage self.maxage = maxage def __str__(self): return f"Недопустимое значение: . " \ f"Возраст должен быть в диапазоне от до "
В функции __str__ определяем текстовое представление класса - по сути сообщение об ошибке.
В конструкторе класса Persoon проверяем переданное для возраста пользователя значение. И если это значение не соответствует определенному диапазону, то генерируем исключение типа PersonAgeException:
raise PersonAgeException(age, minage, maxage)
При применении класса Person нам следует учитывать, что конструктор класса может сгенерировать исключение при передаче некорректного значения. Поэтому создание объектов Person обертывается в конструкцию try..except:
try: tom = Person("Tom", 37) tom.display_info() # Имя: Tom Возраст: 37 bob = Person("Bob", -23) # генерируется исключение типа PersonAgeException bob.display_info() except PersonAgeException as e: print(e) # Недопустимое значение: -23. Возраст должен быть в диапазоне от 1 до 110
И если при вызове конструктора Person будет сгенерировано исключение типа PersonAgeException, то управление программой перейдет к блоку except, который обрабатывает исключения типа PersonAgeException в виде вывода информации об исключении на консоль.
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]
Исключения в 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
Обработка исключений Python — блок Try/Except, блок Finally
В этом материале речь пойдет о блоках try/except , finally и raise . Вместе с тем будет рассмотрено, как создавать собственные исключения в Python.
2. Обработка исключений в Python
Рассмотрим разные типы исключений в Python, которые появляются при срабатывании исключения в коде Python.
3. Блоки try/except
Если код может привести к исключению, его лучше заключить в блок try . Рассмотрим на примере.
try: for i in range(3): print(3/i) except: print("Деление на 0") print("Исключение было обработано")
Программа вывела сообщение, потому что было обработано исключение.
Следом идет блок except . Если не определить тип исключения, то он будет перехватывать любые. Другими словами, это общий обработчик исключений.
Если код в блоке try приводит к исключению, интерпретатор ищет блок except , который указан следом. Оставшаяся часть кода в try исполнена не будет.
Исключения Python особенно полезны, если программа работает с вводом пользователя, ведь никогда нельзя знать, что он может ввести.
a. Несколько except в Python
У одного блока try может быть несколько блоков except . Рассмотрим примеры с несколькими вариантами обработки.
a, b = 1, 0 try: print(a/b) print("Это не будет напечатано") print('10'+10) except TypeError: print("Вы сложили значения несовместимых типов") except ZeroDivisionError: print("Деление на 0")
Когда интерпретатор обнаруживает исключение, он проверяет блоки except соответствующего блока try . В них может быть объявлено, какие типы исключений они обрабатывают. Если интерпретатор находит соответствующее исключение, он исполняет этот блок except .
В первом примере первая инструкция приводит к ZeroDivisionError . Эта ошибка обрабатывается в блоке except , но инструкции в try после первой не исполняются. Так происходит из-за того, что после первого исключения дальнейшие инструкции просто пропускаются. И если подходящий или общий блоки except не удается найти, исключение не обрабатывается. В таком случае оставшаяся часть программы не будет запущена. Но если обработать исключение, то код после блоков except и finally исполнится. Попробуем.
a, b = 1, 0 try: print(a/b) except: print("Вы не можете разделить на 0") print("Будет ли это напечатано?")
Вы не можете разделить на 0 Будет ли это напечатано?
b. Несколько исключений в одном except
Можно использовать один блок except для обработки нескольких исключений. Для этого используются скобки. Без них интерпретатор вернет синтаксическую ошибку.
try: print('10'+10) print(1/0) except (TypeError,ZeroDivisionError): print("Неверный ввод")
Неверный ввод
c. Общий except после всех блоков except
В конце концов, завершить все отдельные блоки except можно одним общим. Он используется для обработки всех исключений, которые не были перехвачены отдельными except .
try: print('1'+1) print(sum) print(1/0) except NameError: print("sum не существует") except ZeroDivisionError: print("Вы не можете разделить на 0") except: print("Что-то пошло не так. ")
Что-то пошло не так.
Здесь первая инструкция блока пытается осуществить операцию конкатенации строки python с числом. Это приводит к ошибке TypeError . Как только интерпретатор сталкивается с этой проблемой, он проверяет соответствующий блок except , который ее обработает.
Отдельную инструкцию нельзя разместить между блоками try и except .
try: print("1") print("2") except: print("3")
Это приведет к синтаксической ошибке.
Но может быть только один общий или блок по умолчанию типа except . Следующий код вызовет ошибку «default 'except:' must be last» :
try: print(1/0) except: raise except: print("Исключение поймано") finally: print("Хорошо") print("Пока")
4. Блок finally в Python
После последнего блока except можно добавить блок finally . Он исполняет инструкции при любых условиях.
try: print(1/0) except ValueError: print("Это ошибка значения") finally: print("Это будет напечатано в любом случае.")
Это будет напечатано в любом случае. Traceback (most recent call last): File “”, line 2, in print(1/0) ZeroDivisionError: division by zero
Стоит обратить внимание, что сообщение с ошибкой выводится после исполнения блока finally . Почему же тогда просто не использовать print ? Но как видно по последнему примеру, блок finally запускается даже в том случае, если перехватить исключение не удается.
А что будет, если исключение перехватывается в except ?
try: print(1/0) except ZeroDivisionError: print(2/0) finally: print("Ничего не происходит")
Ничего не происходит Traceback (most recent call last): File "", line 2, in print(1/0) ZeroDivisionError: division by zero During handling of the above exception, another exception occurred: Traceback (most recent call last): File "", line 4, in print(2/0) ZeroDivisionError: division by zero
Как видите, код в блоке finally исполняется в любом случае.
5. Ключевое слово raise в Python
Иногда нужно будет разбираться с проблемами с помощью вызова исключения. Обычная инструкция print тут не сработает.
raise ZeroDivisionError
Traceback (most recent call last): File "", line 1, in raise ZeroDivisionError ZeroDivisionError
Разберемся на примере операции деления:
a,b=int(input()),int(input()) # вводим 1 затем 0 if b==0: raise ZeroDivisionError
Traceback (most recent call last): File "", line 3, in raise ZeroDivisionError ZeroDivisionError
Здесь ввод пользователя в переменные a и b конвертируется в целые числа. Затем проверяется, равна ли b нулю. Если да, то вызывается ZeroDivisionError .
Что будет, если то же самое добавить в блоки try-except? Добавим следующее в код. Если запустить его, ввести 1 и 0, будет следующий вывод:
a,b=int(input()),int(input()) try: if b==0: raise ZeroDivisionError except: print("Деление на 0") print("Будет ли это напечатано?")
1 0 Деление на 0 Будет ли это напечатано?
Рассмотрим еще несколько примеров, прежде чем двигаться дальше:
raise KeyError
Traceback (most recent call last): File “”, line 1, in raise KeyError KeyError
a. Raise без определенного исключения в Python
Можно использовать ключевое слово raise и не указывая, какое исключение вызвать. Оно вызовет исключение, которое произошло. Поэтому его можно использовать только в блоке except .
try: print('1'+1) except: raise
Traceback (most recent call last): File “”, line 2, in print(‘1’+1) TypeError: must be str, not int
b. Raise с аргументом в Python
Также можно указать аргумент к определенному исключению в raise . Делается это с помощью дополнительных деталей исключения.
raise ValueError("Несоответствующее значение")
Traceback (most recent call last): File "", line 1, in raise ValueError("Несоответствующее значение") ValueError: Несоответствующее значение
6. assert в Python
Утверждение (assert) — это санитарная проверка для вашего циничного, параноидального «Я». Оно принимает инструкцию в качестве аргумента и вызывает исключение Python, если возвращается значение False . В противном случае выполняет операцию No-operation (NOP).
assert(True) # код работает дальше
Если бы инструкция была False ?
assert(1==0)
Traceback (most recent call last): File “”, line 1, in assert(1==0) AssertionError
Возьмем другой пример:
try: print(1) assert 2+2==4 print(2) assert 1+2==4 print(3) except: print("assert False.") raise finally: print("Хорошо") print("Пока")
1 2 assert False. Хорошо Traceback (most recent call last): File “”, line 5, in assert 1+2==4 AssertionError
Утверждения можно использовать для проверки валидности ввода и вывода в функции.
a. Второй аргумент для assert
Можно предоставить второй аргумент, чтобы дать дополнительную информацию о проблеме.
assert False,"Это проблема"
Traceback (most recent call last): File “”, line 1, in assert False,”Это проблема” AssertionError: Это проблема
7. Объявление собственных исключений Python
Наконец, рассмотрим процесс создания собственных исключений. Для этого создадим новый класс из класса Exception . Потом его можно будет вызывать как любой другой тип исключения.
class MyError(Exception): print("Это проблема") raise MyError("ошибка MyError")
Traceback (most recent call last): File “”, line 1, in raise MyError(“ошибка MyError”) MyError: ошибка MyError
Вот и все, что касается обработки исключений в Python.
8. Вывод: обработка исключений Python
Благодаря этой статье вы сможете обеспечить дополнительную безопасность своему коду. Все благодаря возможности обработки исключений Python, их вызова и создания собственных.
