Как я могу вызвать исключение в Python, чтобы потом его можно было перехватить через except
блок?
Как вручную сгенерировать / вызвать исключение в Python?
Будьте конкретны в своем сообщении, например:
raise ValueError('A very specific bad thing happened.')
Избегайте повышения общего Exception
. Чтобы поймать его, вам нужно поймать все другие более конкретные исключения, которые подкласс его.
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',)
И более конкретные уловы не поймут общее исключение:
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
атрибут Exception
объекта. Например:
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]
Если вы хотите, вы можете изменить то, что происходит с вашим новым рейзом - например, установить новый args
для экземпляра:
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 вы можете связать исключения, которые сохраняют обратные трассировки:
raise RuntimeError('specific message') from error
Быть в курсе:
Они могут легко спрятаться и даже попасть в рабочий код. Вы хотите вызвать исключение, и выполнение их вызовет исключение, но не то, которое намеревалось!
Допустимо в 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.')
raise
это то, что мне нужно, чтобы иметь возможность выполнять пользовательскую отладку ошибок на нескольких уровнях выполнения кода, не нарушая трассировку стека.raise sys.exc_info()[0], (sys.exc_info()[1], my_extra_info), sys.exc_info()[2]
кажется, делает то, что я хочу, и у меня никогда не было проблем с этим. Но это кажется хакерским, а не принятой практикой. Есть ли способ лучше?Exception
вашего родительского класса - вы можете создать подкласс чего-то более конкретного, и это следует делать, если это имеет смысл.AppError
исключение. Может быть лучше использовать встроенную ошибку, такую какAttributeError
Не может быть намного более питоническим, чем это:
Посмотрите документы поднятия для python, если вам нужна дополнительная информация.
источник
В Python3 есть 4 различных синтаксиса для выявления исключений:
Если вы используете,
raise exception (args)
чтобы вызвать исключение, оноargs
будет напечатано при печати объекта исключения - как показано в примере ниже.raise
заявление без каких-либо аргументов повторно вызывает последнее исключение. Это полезно, если вам необходимо выполнить некоторые действия после перехвата исключения, а затем повторно вызвать его. Но если раньше не было никаких исключений,raise
утверждение порождаетTypeError
исключение.Этот оператор используется для создания цепочки исключений, в которой исключение, вызываемое в ответ на другое исключение, может содержать сведения об исходном исключении - как показано в примере ниже.
Вывод:
источник
exception(args)
болееexception (args)
raise exception(args) from None
можно сказать, что в настоящее время активное исключение было обработано и больше не представляет интереса. В противном случае, если вы вызовете исключение внутриexcept
блока, и оно не будет обработано, трассировки для обоих исключений будут показаны отделенными сообщением «Во время обработки вышеупомянутого исключения произошло другое исключение»Для общего случая, когда вам нужно выдать исключение в ответ на некоторые непредвиденные условия, и который вы никогда не намереваетесь отловить, а просто быстро потерпеть неудачу, чтобы дать вам возможность отладки оттуда, если это когда-нибудь произойдет, - наиболее логичным кажется
AssertionError
:источник
ValueError
чемAssertionError
потому, что нет проблем с утверждением (потому что здесь ничего не делается) - проблема со значением. Если вы действительно хотитеAssertionError
в этом случае, напишитеassert distance > 0, 'Distance must be positive'
. Но вы не должны проверять ошибки таким образом, потому что утверждения можно отключить (python -O
).-O
.Сначала прочтите существующие ответы, это всего лишь дополнение.
Обратите внимание, что вы можете вызывать исключения с аргументами или без них.
Пример:
Выход из программы, но вы можете знать, что произошло. Так что вы можете использовать это.
это выведет "программу вышла" в stderr перед закрытием программы.
источник
raise SystemExit()
будет ли лучший выбор? Почему первый вообще работает?Еще один способ выбросить исключение
assert
. Вы можете использовать assert для проверки выполнения условия, если нет, то оно будет выполненоAssertionError
. Для более подробной информации посмотрите здесь .источник
Просто чтобы заметить: бывают случаи, когда вы действительно хотите обрабатывать общие исключения. Если вы обрабатываете кучу файлов и регистрируете свои ошибки, вы можете захотеть отследить любую ошибку, которая возникает для файла, зарегистрировать ее и продолжить обработку остальных файлов. В этом случае
заблокировать хороший способ сделать это. Вы все равно захотите использовать
raise
конкретные исключения, чтобы знать, что они означают.источник
Для этого вам следует изучить оператор повышения python. Он должен храниться внутри блока try. Пример -
источник