python: как узнать, какой тип исключения произошел?
у меня есть функция, вызываемая из основной программы:
try:
someFunction()
except:
print "exception happened!"
но в середине выполнения функции он вызывает исключение, поэтому он переходит к except часть.
как я могу точно видеть, что произошло в someFunction(), которая вызвала исключение произойдет?
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