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

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

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

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

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

16 ответов

Решение

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

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

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

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

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 доведен до сведения пользователя в упущенном виде! Его печати, как показано выше, может быть недостаточно, если сообщение скрыто во множестве других сообщений. Неспособность привлечь внимание пользователей равносильна проглатыванию всех исключений, и если есть одно впечатление, которое вы должны были оставить после прочтения ответов на этой странице, это то, что это не очень хорошая вещь. Завершение блока кроме raise Заявление решит проблему путем прозрачного пересмотра исключения, которое было поймано.

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

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

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

import traceback
print traceback.format_exc()

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

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

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

import pdb
pdb.post_mortem()

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

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

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 не включает calculate() функция от линии 9 который является источником оригинального исключения e,

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

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

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

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

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

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

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

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

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

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

try: 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's 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))

Использоватьtypeкласс иasзаявление

      try:#code
except Exception as e:
     m=type(e)
     #m is the class of the exception
     strm=str(m)
     #strm is the string of m

Надеюсь, это поможет еще немного

import sys
varExcepHandling, varExcepHandlingZer = 2, 0
try:
  print(varExcepHandling/varExcepHandlingZer)
except Exception as ex: 
  print(sys.exc_info())

'sys.exc_info()'вернет кортеж, если вы хотите использовать только имя класса исключения'sys.exc_info()[0]'

Примечание:- если вы хотите увидеть все классы исключений, просто напишите dir(__builtin__)

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

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 был удален по ошибке.

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

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

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/

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

except Exception as ex:

а потом просто print ex вот так:

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

Используйте ниже как для типа исключения, так и для текста исключения

import sys
print(str(sys.exc_info()[0]).split(' ')[1].strip('>').strip("'")+"-"+(str(sys.exc_info()[1])))

если вам нужен только тип исключения: Используйте ->

import sys
print(str(sys.exc_info()[0]).split(' ')[1].strip('>').strip("'"))

Спасибо Раджешвар

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

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

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

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

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

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

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

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