Вызов (выбрасывание) исключения в 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

Другие вопросы по тегам