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



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



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


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



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

2222   12  

12 ответов:

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

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

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

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

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 не пойман выше код, который, как правило, то, что вы хотите. Смотрите иерархия исключений.

если вы также хотите получить тот же stacktrace, если вы не поймаете исключение, вы можете получить это так (все еще внутри предложения 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()

я нашел этот последний метод, чтобы быть бесценным при охоте на ошибки.

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

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    

обратите внимание, что трассировка не включает

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

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

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

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

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

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

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

попробовать: someFunction() кроме исключения, искл:

#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))

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

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.

в приведенном примере одним из решений может быть поиск данных приложения, хранящихся где-то еще, скажем, если " приложение.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

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

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

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

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

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

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

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

Comments

    Ничего не найдено.