Вызов (выбрасывание) исключения в Python вручную
Как я могу вызвать исключение в Python, чтобы потом его можно было перехватить через except
блок?
12 ответов
Как вручную сгенерировать / вызвать исключение в Python?
Будьте конкретны в своем сообщении, например:
raise ValueError('A very specific bad thing happened.')
Не выдвигайте общие исключения
Избегайте поднятия общего исключения. Чтобы поймать его, вам нужно поймать все другие более конкретные исключения, которые подкласс его.
Проблема 1: Скрытие ошибок
raise Exception('I know Python!') # Don't! If you catch, likely to hide bugs.
Например:
def demo_bad_catch():
try:
raise ValueError('Represents a hidden bug, do not catch this')
raise Exception('This is the exception you expect to handle')
except Exception as error:
print('Caught this error: ' + repr(error))
>>> demo_bad_catch()
Caught this error: ValueError('Represents a hidden bug, do not catch this',)
Проблема 2: не поймать
и более конкретные уловы не поймут общее исключение:
def demo_no_catch():
try:
raise Exception('general exceptions not caught by specific handling')
except ValueError as e:
print('we will not catch exception: Exception')
>>> demo_no_catch()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in demo_no_catch
Exception: general exceptions not caught by specific handling
Лучшие практики: raise
заявление
raise ValueError('A very specific bad thing happened')
что также позволяет произвольному количеству аргументов быть переданным конструктору:
raise ValueError('A very specific bad thing happened', 'foo', 'bar', 'baz')
Эти аргументы доступны для args
атрибут на объекте исключения. Например:
try:
some_code_that_may_raise_our_value_error()
except ValueError as err:
print(err.args)
печать
('message', 'foo', 'bar', 'baz')
В Python 2.5 актуальный message
Атрибут BaseException был добавлен в пользу поощрения пользователей к созданию подклассов исключений и прекращению их использования. args
, но введение message
и первоначальное осуждение аргументов было убрано.
Лучшие практики:except
пункт
Находясь внутри предложения исключений, вы можете захотеть, например, записать, что произошла ошибка определенного типа, а затем повторно вызвать ее. Лучший способ сделать это, сохранив трассировку стека, - это использовать выражение чуть-чуть. Например:
logger = logging.getLogger(__name__)
try:
do_something_in_app_that_breaks_easily()
except AppError as error:
logger.error(error)
raise # just this!
# raise AppError # Don't do this, you'll lose the stack trace!
Не изменяйте свои ошибки... но если вы настаиваете.
Вы можете сохранить трассировку стека (и значение ошибки) с помощьюsys.exc_info()
, но это гораздо более подвержен ошибкам и имеет проблемы совместимости между Python 2 и 3, предпочитают использовать голыеraise
повторно поднять.
Объяснить -sys.exc_info()
возвращает тип, значение и трассировку.
type, value, traceback = sys.exc_info()
Это синтаксис в Python 2 - обратите внимание, что это не совместимо с Python 3:
raise AppError, error, sys.exc_info()[2] # avoid this.
# Equivalently, as error *is* the second object:
raise sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2]
Если вы хотите, вы можете изменить то, что происходит с вашим новым рейзом - например, установить новые аргументы для экземпляра:
def error():
raise ValueError('oops!')
def catch_error_modify_message():
try:
error()
except ValueError:
error_type, error_instance, traceback = sys.exc_info()
error_instance.args = (error_instance.args[0] + ' <modification>',)
raise error_type, error_instance, traceback
И мы сохранили весь трассировку при модификации аргументов. Обратите внимание, что это не лучшая практика инедопустимый синтаксис в Python 3 (что делает совместимость намного сложнее).
>>> catch_error_modify_message()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in catch_error_modify_message
File "<stdin>", line 2, in error
ValueError: oops! <modification>
В Python 3:
raise error.with_traceback(sys.exc_info()[2])
Опять же: избегайте ручного манипулирования трассировками. Это менее эффективно и более подвержено ошибкам. И если вы используете потоки иsys.exc_info
вы можете даже получить неправильный след (особенно, если вы используете обработку исключений для потока управления - чего я бы лично избегал).
Python 3, цепочка исключений
В Python 3 вы можете связывать исключения, которые сохраняют обратные трассировки:
raise RuntimeError('specific message') from error
Быть в курсе:
- это позволяет изменить тип возникшей ошибки, и
- это не совместимо с Python 2.
Устаревшие методы:
Они могут легко спрятаться и даже попасть в рабочий код. Вы хотите вызвать исключение, и выполнение их вызовет исключение, но не то, которое предназначалось!
Допустимо в Python 2, но не в Python 3:
raise ValueError, 'message' # Don't do this, it's deprecated!
Действует только в гораздо более старых версиях Python (2.4 и ниже), вы все равно можете увидеть людей, поднимающих строки:
raise 'message' # really really wrong. don't do this.
Во всех современных версиях это фактически вызовет TypeError, потому что вы не вызываете тип BaseException. Если вы не проверяете правильное исключение и у вас нет рецензента, который знает о проблеме, он может попасть в производство.
Пример использования
Я поднимаю исключения, чтобы предупредить потребителей моего API, если они используют его неправильно:
def api_func(foo):
'''foo should be either 'baz' or 'bar'. returns something very useful.'''
if foo not in _ALLOWED_ARGS:
raise ValueError('{foo} wrong, use "baz" or "bar"'.format(foo=repr(foo)))
Создайте свои собственные типы ошибок, когда уместно
"Я хочу нарочно сделать ошибку, чтобы она пошла в исключение"
Вы можете создавать свои собственные типы ошибок, если вы хотите указать, что что-то не так с вашим приложением, просто создайте подкласс соответствующей точки в иерархии исключений:
class MyAppLookupError(LookupError):
'''raise this when there's a lookup error for my app'''
и использование:
if important_key not in resource_dict and not ok_to_be_missing:
raise MyAppLookupError('resource is missing, and that is not ok.')
НЕ ДЕЛАЙТЕ ЭТОГО. Поднятие голого
Exception
абсолютно не правильно делать; см . отличный ответ Аарона Холла.
Не могу получить гораздо более питонического, чем это:
raise Exception("I know python!")
Если вам нужна дополнительная информация, смотрите документацию по поднятиям для python.
В Python3 есть 4 различных синтаксиса для выявления исключений:
1. raise exception
2. raise exception (args)
3. raise
4. raise exception (args) from original_exception
1. поднять исключение против 2. поднять исключение (аргументы)
Если вы используете raise exception (args)
поднять исключение, то args
будет напечатан при печати объекта исключения - как показано в примере ниже.
#raise exception (args)
try:
raise ValueError("I have raised an Exception")
except ValueError as exp:
print ("Error", exp) # Output -> Error I have raised an Exception
#raise execption
try:
raise ValueError
except ValueError as exp:
print ("Error", exp) # Output -> Error
3.raise
raise
заявление без каких-либо аргументов повторно вызывает последнее исключение. Это полезно, если вам нужно выполнить некоторые действия после перехвата исключения, а затем повторно вызвать его. Но если не было никаких исключений раньше, raise
заявление поднимает TypeError
Исключение.
def somefunction():
print("some cleaning")
a=10
b=0
result=None
try:
result=a/b
print(result)
except Exception: #Output ->
somefunction() #some cleaning
raise #Traceback (most recent call last):
#File "python", line 8, in <module>
#ZeroDivisionError: division by zero
4. поднять исключение (аргументы) из оригинального исключения
Этот оператор используется для создания цепочки исключений, в которой исключение, вызываемое в ответ на другое исключение, может содержать сведения об исходном исключении - как показано в примере ниже.
class MyCustomException(Exception):
pass
a=10
b=0
reuslt=None
try:
try:
result=a/b
except ZeroDivisionError as exp:
print("ZeroDivisionError -- ",exp)
raise MyCustomException("Zero Division ") from exp
except MyCustomException as exp:
print("MyException",exp)
print(exp.__cause__)
Выход:
ZeroDivisionError -- division by zero
MyException Zero Division
division by zero
Для общего случая, когда вам нужно выдать исключение в ответ на некоторые непредвиденные условия, и который вы никогда не намереваетесь отловить, а просто быстро потерпеть неудачу, чтобы дать вам возможность отладки оттуда, если это когда-либо произойдет, - наиболее логичным кажется AssertionError
:
if 0 < distance <= RADIUS:
#Do something.
elif RADIUS < distance:
#Do something.
else:
raise AssertionError("Unexpected value of 'distance'!", distance)
Сначала прочтите существующие ответы, это всего лишь дополнение.
Обратите внимание, что вы можете вызывать исключения с аргументами или без них.
Пример:
raise SystemExit
Выход из программы, но вы можете знать, что произошло. Так что вы можете использовать это.
raise SystemExit("program exited")
это выведет "программу вышла" в stderr перед закрытием программы.
Чтобы поймать все исключения, используйте
BaseException
, он находится на вершине иерархии исключений.
try:
#Do something
except BaseException as error:
print('An exception occurred: {}'.format(error))
Приведенный выше код поддерживает Python 2.7 до последней версии.
Ссылка: https://docs.python.org/3.9/library/exceptions.html#exception-hierarchy
Просто чтобы заметить: бывают случаи, когда вы действительно хотите обрабатывать общие исключения. Если вы обрабатываете кучу файлов и регистрируете свои ошибки, вы можете захотеть отследить любую ошибку, которая возникает для файла, зарегистрировать ее и продолжить обработку остальных файлов. В этом случае попробуйте: кроме исключений: это хороший способ сделать это. Вы все еще хотите поднять конкретные исключения, чтобы вы знали, что они означают, хотя.
Еще один способ создать исключение assert
, Вы можете использовать assert для проверки выполнения условия, если нет, то оно будет повышено AssertionError
, Для более подробной информации посмотрите здесь.
def avg(marks):
assert len(marks) != 0,"List is empty."
return sum(marks)/len(marks)
mark2 = [55,88,78,90,79]
print("Average of mark2:",avg(mark2))
mark1 = []
print("Average of mark1:",avg(mark1))
Для этого вы должны выучить инструкцию Raise в Python. Он должен храниться в блоке try. Пример -
try:
raise TypeError #remove TypeError by any other error if you want
except TypeError:
print('TypeError raised')
Вы также можете создать собственные исключения. Например, если вы пишете библиотеку, очень полезно создать базовый класс исключения для вашего модуля, а затем иметь настраиваемые под-исключения, чтобы быть более конкретными.
Вы можете добиться этого следующим образом:
class MyModuleBaseClass(Exception):
pass
class MoreSpecificException(MyModuleBaseClass):
pass
# To raise custom exceptions, you can just
# use the raise keyword
raise MoreSpecificException
raise MoreSpecificException('message')
Если вас не интересует настраиваемый базовый класс, вы можете просто унаследовать свои настраиваемые классы исключений от обычного класса исключений, например
Exception
,
TypeError
,
ValueError
, так далее.
Если вас не волнует, какая ошибка возникает, вы можете использовать, чтобы поднять:
>>> assert False, "Manually raised error"
Traceback (most recent call last):
File "<pyshell#24>", line 1, in <module>
assert False, "Manually raised error"
AssertionError: Manually raised error
>>>
В
assert
ключевое слово вызывает
AssertionError
если условие есть, в этом случае мы указали
False
напрямую, поэтому он вызывает ошибку, но чтобы у него был текст, который мы хотим, чтобы он поднял, мы добавляем запятую и указываем текст ошибки, который мы хотим, в этом случае я написал
Manually raised error
и это поднимет его с этим текстом.
если вас не волнует возбужденное исключение, выполните:
def crash(): return 0/0
the good old division be 0