Python: Как узнать, какой тип исключения произошел?

У меня есть функция, вызываемая основной программой:

try:
    someFunction()
except:
    print "exception happened!"

но в середине выполнения функции он вызывает исключение, поэтому он переходит к части except.

Как я могу точно увидеть, что произошло в someFunction(), вызвавшем исключение?

Ответ 1

Другие ответы на все указывают на то, что вы не должны улавливать общие исключения, но никто, кажется, не хочет говорить вам, почему это важно для понимания, когда вы можете нарушить "правило". Здесь объяснение. В принципе, это так, что вы не скрываете:

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

  • Существующие исключения как диалоги в графическом интерфейсе
  • Передавать исключения из рабочего потока или процесса в управляющий поток или процесс в многопоточном или многопроцессорном приложении.

Итак, как поймать общее исключение? Есть несколько способов. Если вы просто хотите объект исключения, сделайте следующее:

try:
    someFunction()
except Exception as ex:
    template = "An exception of type {0} occurred. Arguments:\n{1!r}"
    message = template.format(type(ex).__name__, ex.args)
    print message

Удостоверьтесь, что message доведено до сведения пользователя очень трудно! Печатать его, как показано выше, может быть недостаточно, если сообщение захоронено множеством других сообщений. Неспособность привлечь внимание пользователей равносильна проглатыванию всех исключений, и если у вас будет какое-то впечатление, что вам следует уйти после прочтения ответов на этой странице, это не очень хорошо. Завершение блока except с помощью оператора raise устраняет проблему путем прозрачного повторения исключения, которое было обнаружено.

Разница между приведенным выше и использованием только except: без каких-либо аргументов двояка:

  • Голый except: не дает вам объект исключения для проверки
  • Исключения SystemExit, KeyboardInterrupt и GeneratorExit не пойманы указанным выше кодом, что обычно является тем, что вы хотите. См. Иерархию исключений .

Если вы также хотите получить ту же стек, что и вы, если не поймаете исключение, вы можете получить это так (все еще внутри предложения except):

import traceback
print traceback.format_exc()

Если вы используете модуль logging, вы можете распечатать исключение в журнале (вместе с сообщением) следующим образом:

import logging
log = logging.getLogger()
log.exception("Message for you, sir!")

Если вы хотите углубиться и изучить стек, посмотреть на переменные и т.д., используйте функцию post_mortem pdb модуль внутри блока except:

import pdb
pdb.post_mortem()

Я нашел этот последний метод бесценным при поиске ошибок.

Ответ 2

Получите имя класса, к которому принадлежит объект исключения:

e.__class__.__name__

и использование функции print_exc() также напечатает трассировку стека, которая является важной информацией для любого сообщения об ошибке.

Как это:

from traceback import print_exc

class CustomException(Exception): pass

try:
    raise CustomException("hi")
except Exception, e:
    print 'type is:', e.__class__.__name__
    print_exc()
    # print "exception happened!"

Вы получите вывод, как это:

type is: CustomException
Traceback (most recent call last):
  File "exc.py", line 7, in <module>
    raise CustomException("hi")
CustomException: hi

И после печати и анализа код может решить не обрабатывать исключение, а просто выполнить raise:

from traceback import print_exc

class CustomException(Exception): pass

def calculate():
    raise CustomException("hi")

try:
    calculate()
except Exception, e:
    if e.__class__ == CustomException:
        print 'special case of', e.__class__.__name__, 'not interfering'
        raise
    print "handling exception"

Выход:

special case of CustomException not interfering

И переводчик печатает исключение:

Traceback (most recent call last):
  File "test.py", line 9, in <module>
    calculate()
  File "test.py", line 6, in calculate
    raise CustomException("hi")
__main__.CustomException: hi

После raise исходное исключение продолжает распространяться далее вверх по стеку вызовов. (Остерегайтесь возможных ловушек). Если вы возбуждаете новое исключение, то появляется новый (более короткий) след стека.

from traceback import print_exc

class CustomException(Exception): pass

def calculate():
    raise CustomException("hi")

try:
    calculate()
except Exception, e:
    if e.__class__ == CustomException:
        print 'special case of', e.__class__.__name__, 'not interfering'
        #raise CustomException(e.message)
        raise e
    print "handling exception"

Выход:

special case of CustomException not interfering
Traceback (most recent call last):
  File "test.py", line 13, in <module>
    raise CustomException(e.message)
__main__.CustomException: hi    

Обратите внимание, что traceback не включает функцию calc calculate() из строки 9 которая является источником исходного исключения e.

Ответ 3

Обычно вы не должны улавливать все возможные исключения с помощью try: ... except, поскольку это слишком широко. Просто поймайте те, которые, как ожидается, произойдут по любой причине. Если вам действительно нужно, например, если вы хотите узнать больше о какой-либо проблеме во время отладки, вы должны сделать

try:
    ...
except Exception as ex:
    print ex # do whatever you want for debugging.
    raise    # re-raise exception.

Ответ 4

Если somefunction - очень плохо кодированная устаревшая функция, вам не нужно то, что вы просите.

Используйте несколько except для обработки различными способами различных исключений:

try:
    someFunction()
except ValueError:
    # do something
except ZeroDivision:
    # do something else

Главное, что вы не должны ловить общее исключение, а только те, которые вам нужны. Я уверен, что вы не хотите замаскировать неожиданные ошибки или ошибки.

Ответ 5

Большинство ответов указывают на except (…) as (…): синтаксис (правильно), но в то же время никто не хочет говорить о слоне в комнате, где слоном является sys.exc_info(). Из документации модуля sys (выделение мое):

Эта функция возвращает кортеж из трех значений, которые дают информацию об исключении, которое в данный момент обрабатывается.
(...)
Если нигде в стеке не обрабатывается исключение, возвращается кортеж, содержащий три значения None. В противном случае возвращаются значения (тип, значение, обратная связь). Их значение таково: тип получает тип обрабатываемого исключения (подкласс BaseException); значение получает экземпляр исключения (экземпляр типа исключения); traceback получает объект traceback (см. Справочное руководство), который инкапсулирует стек вызовов в точке, где первоначально произошло исключение.

Я думаю, что sys.exc_info() можно рассматривать как самый прямой ответ на первоначальный вопрос: как узнать, какой тип исключения произошел?

Ответ 6

попробовать:   SomeFunction() кроме Exception, exc:

#this is how you get the type
excType = exc.__class__.__name__

#here we are printing out information about the Exception
print 'exception type', excType
print 'exception msg', str(exc)

#It easy to reraise an exception with more information added to it
msg = 'there was a problem with someFunction'
raise Exception(msg + 'because of %s: %s' % (excType, exc))

Ответ 7

Вот как я обрабатываю свои исключения. Идея состоит в том, чтобы попытаться решить проблему, если это легко, а затем добавить более желательное решение, если это возможно. Не решайте проблему в коде, который генерирует исключение, или этот код теряет следы исходного алгоритма, который должен быть записан в точку. Однако передайте данные, необходимые для решения проблемы, и верните лямбду на всякий случай, если вы не сможете решить проблему за пределами кода, который ее генерирует.

path = 'app.p'

def load():
    if os.path.exists(path):
        try:
            with open(path, 'rb') as file:
                data = file.read()
                inst = pickle.load(data)
        except Exception as e:
            inst = solve(e, 'load app data', easy=lambda: App(), path=path)()
    else:
        inst = App()
    inst.loadWidgets()

# e.g. A solver could search for app data if desc='load app data'
def solve(e, during, easy, **kwargs):
    class_name = e.__class__.__name__
    print(class_name + ': ' + str(e))
    print('\t during: ' + during)
    return easy

Пока, поскольку я не хочу думать тангенциально с целью моего приложения, я не добавил никаких сложных решений. Но в будущем, когда я больше знаю о возможных решениях (поскольку приложение больше разработано), я мог бы добавить в словарь решений, индексированных с помощью during.

В показанном примере одним из решений может быть поиск данных приложения, хранящихся в другом месте, скажем, если файл app.p был удален по ошибке.

На данный момент, поскольку запись обработчика исключений не является умной идеей (мы пока не знаем, как лучше ее решить, потому что дизайн приложения будет развиваться), мы просто возвращаем простое исправление, которое должно действовать как мы "запуск приложения в первый раз (в этом случае).

Ответ 8

Чтобы добавить к Lauritz ответ, я создал декоратор/обертку для обработки исключений и журналы оберток, тип исключения которых произошел.

class general_function_handler(object):
    def __init__(self, func):
        self.func = func
    def __get__(self, obj, type=None):
        return self.__class__(self.func.__get__(obj, type))
    def __call__(self, *args, **kwargs):
        try:
            retval = self.func(*args, **kwargs)
        except Exception, e :
            logging.warning('Exception in %s' % self.func)
            template = "An exception of type {0} occured. Arguments:\n{1!r}"
            message = template.format(type(e).__name__, e.args)
            logging.exception(message)
            sys.exit(1) # exit on all exceptions for now
        return retval

Это может быть вызвано методом класса или отдельной функцией с декоратором:

@general_function_handler

Посмотрите мой блог о полном примере: http://ryaneirwin.wordpress.com/2014/05/31/python-decorators-and-exception-handling/

Ответ 9

Вы можете начать, как рекомендовал Лауриц, с помощью:

except Exception as ex:

а затем просто до print ex так:

try:
    #your try code here
except Exception as ex:
    print ex

Ответ 10

Фактическое исключение можно записать следующим образом:

try:
    i = 1/0
except Exception as e:
    print e

Вы можете узнать больше об исключениях из Учебник по Python.

Ответ 11

Ваш вопрос: "Как я могу точно увидеть, что произошло в someFunction(), вызвавшем исключение?"

Мне кажется, что вы не спрашиваете о том, как обрабатывать непредвиденные исключения в производственном коде (как и многие ответы), но как узнать, что вызывает конкретное исключение во время разработки.

Самый простой способ - использовать отладчик, который может остановиться, где происходит неперехваченное исключение, предпочтительно не выходить, чтобы вы могли проверять переменные. Например, PyDev в Eclipse с открытым исходным кодом может это сделать. Чтобы включить это в Eclipse, откройте перспективу отладки, выберите Manage Python Exception Breakpoints в меню Run и проверьте Suspend on uncaught exceptions.

Ответ 12

Просто воздержитесь от того, чтобы поймать исключение и трассировку, которую печатают Python, скажут вам, что произошло.