Вызов (выбрасывание) исключения вручную в Python - PullRequest
1921 голосов
/ 13 января 2010

Как я могу вызвать исключение в Python, чтобы впоследствии его можно было перехватить с помощью блока except?

Ответы [ 7 ]

2452 голосов
/ 05 июня 2014

Как вручную вызвать / вызвать исключение в Python?

Используйте самый специфический конструктор исключений, который семантически соответствует вашей проблеме .

Будьте конкретны в своем сообщении, например ::10000

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 объекта Exception. Например:

try:
    some_code_that_may_raise_our_value_error()
except ValueError as err:
    print(err.args)

отпечатков

('message', 'foo', 'bar', 'baz')    

В Python 2.5 в BaseException был добавлен действительный атрибут message, чтобы побудить пользователей создавать подклассы исключений и прекратить использовать 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>

In 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.')
528 голосов
/ 13 января 2010

НЕ ДЕЛАЙТЕ ЭТОГО . Поднять голый Exception абсолютно не правильная вещь; см. Отличный ответ Аарона Холла .

Не может быть гораздо более питоническим, чем это:

raise Exception("I know python!")

См. оператор поднятия для * Python , если вам нужна дополнительная информация.

32 голосов
/ 19 мая 2015

Для общего случая, когда вам нужно выдать исключение в ответ на некоторые непредвиденные условия, и которое вы никогда не намереваетесь перехватить, а просто быстро потерпеть неудачу, чтобы позволить вам отлаживать оттуда, если это когда-нибудь произойдет, - самый логичный кажется AssertionError:

if 0 < distance <= RADIUS:
    #Do something.
elif RADIUS < distance:
    #Do something.
else:
    raise AssertionError("Unexpected value of 'distance'!", distance)
31 голосов
/ 08 ноября 2016

В 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 Exception.

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. вызвать исключение (аргументы) из original_exception

Этот оператор используется для создания цепочки исключений, в которой исключение, вызываемое в ответ на другое исключение, может содержать сведения об исходном исключении, как показано в примере ниже.

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
10 голосов
/ 29 марта 2017

Сначала прочитайте существующие ответы, это просто дополнение.

Обратите внимание, что вы можете вызывать исключения с аргументами или без них.

Пример:

raise SystemExit

выходит из программы, но вы можете знать, что произошло. Так что вы можете использовать это.

raise SystemExit("program exited")

это напечатает "программу вышла" в stderr перед закрытием программы.

0 голосов
/ 27 февраля 2019

Другой способ вызвать исключение - 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))
0 голосов
/ 03 декабря 2018

Заметьте: бывают случаи, когда вы действительно хотите обрабатывать общие исключения. Если вы обрабатываете кучу файлов и регистрируете свои ошибки, вы можете захотеть отследить любую ошибку, которая возникает для файла, зарегистрировать ее и продолжить обработку остальных файлов. В этом случае try except Exception: блокирует хороший способ сделать это. Вы все равно захотите raise конкретных исключений, чтобы вы знали, что они означают.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...