python: как узнать, какое исключение произошло?
у меня есть функция, вызываемая из основной программы:
try:
someFunction()
except:
print "exception happened!"
но в середине выполнения функции он вызывает исключение, поэтому он переходит к except
часть.
как я могу точно видеть, что произошло в someFunction()
это вызвало исключение?
12 ответов
другие ответы все указывают на то, что вы не должны ловить общие исключения, но никто, кажется, не хочет сказать вам, почему, что важно для понимания, когда вы можете нарушить "правило". здесь объяснение. В принципе, это так, что вы не скрываете:
- тот факт, что произошла ошибка
- специфика ошибке (ошибка скрытия антипаттерна)
так долго, как вы берете старайтесь не делать ничего из этого, это нормально, чтобы поймать общее исключение. Например, вы можете предоставить информацию об исключении пользователю другим способом, например:
- настоящие исключения как диалоги в GUI
- перенос исключений из рабочего потока или процесса в управляющий поток или процесс в многопоточном или многопроцессорном приложении
Итак, как поймать общее исключение? Есть несколько способов. Если вы просто хотите объект исключения, сделайте это так:
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
statement исправит проблему, прозрачно перезапустив исключение, которое было поймано.
разница между вышеуказанным и использованием just 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
обратите внимание, как traceback не включает
вы обычно не должны ловить все возможные исключения с 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 (), что вызвало исключение?"
мне кажется, что вы спрашиваете не о том, как обрабатывать непредвиденные исключения в производственном коде (как предполагалось во многих ответах), а как узнать, что вызывает конкретное исключение во время разработки.
самый простой способ-использовать отладчик, который может останавливаться там, где происходит исключение uncaught, предпочтительно не выходя, чтобы вы могли проверьте переменные. Например, PyDev в Eclipse с открытым исходным кодом IDE может это сделать. Чтобы включить это в Eclipse, откройте перспективу отладки, выберите Manage Python Exception Breakpoints
на и чека Suspend on uncaught exceptions
.
просто воздержитесь от ловли исключения и трассировки, которую печатает Python, расскажет вам, какое исключение произошло.