2012-03-22 6 views
119

У меня есть функция под названием основной программы:python: Как узнать, какой тип исключения произошел?

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

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

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

+5

Никогда не используйте голые 'except:' (без голого 'рейза'), кроме * возможно * один раз для каждой программы, и предпочтительно не тогда. –

+0

Если вы используете несколько опций 'except', вам не нужно проверять тип исключения, это обычно делается для того, чтобы действовать в соответствии с конкретным типом исключения. –

+1

Если вы беспокоитесь о типе исключения, это связано с тем, что вы уже рассмотрели, какие типы исключений логически могут возникнуть. –

ответ

208

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

  • тот факт, что произошла ошибка
  • специфику возникшей ошибки (error hiding antipattern)

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

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

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

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

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

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

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

+0

traceback.print_exc() сделал бы то же самое, что и ваша более сложная «.join-вещь», я думаю. – Gurgeh

+1

@ Gurgeh Да, но я не знаю, хочет ли он распечатать его или сохранить в файл или записать его или сделать с ним что-то еще. –

+0

Я не остановился, но я бы сказал, что это потому, что вы должны были положить огромный толстый толчок в начале, говоря: «Вам не нужно ничего этого, но вот как это можно сделать **. И, возможно, потому, что вы предлагаете поймать общее исключение. –

12

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

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

Использование слова «никогда» здесь никогда не было так неправильно. Я использую 'try: ... except Exception:' вокруг множества вещей, например. использование сетевых зависимых библиотек или сборщик данных, которые могут получить от нее странные вещи. Естественно, у меня тоже есть правильная регистрация. Это очень важно, чтобы программа продолжала работать в случае одной ошибки во входных данных. – thnee

+0

Когда-либо пытались поймать все исключения, которые могли быть подняты при отправке электронной почты с помощью 'smtplib'? – linusg

+0

Могут быть некоторые особые случаи, когда требуется перехват всех исключений, но на общем уровне вы должны просто поймать то, что ожидаете, чтобы случайно не скрыть ошибки, которые вы не ожидали. Конечно, хорошая регистрация - тоже хорошая идея. – hochl

0

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

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

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

17

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

e.__class__.__name__ 

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

Как это:

from traceback import print_exc 

class dazhuangcao(Exception): pass 

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

вы получите такой вывод:

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

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

7

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

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

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

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

+3

Если вы используете стороннюю библиотеку, вы можете не знать, какие исключения будут возникать внутри нее. Как вы можете их поймать отдельно? – stackoverflowuser2010

5

попробовать: 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)) 
0

Чтобы добавить ответ 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/

0

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

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

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

0

Вы можете начать как Lauritz рекомендуется с:

except Exception as ex: 

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

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

Можете ли вы немного разобраться, чтобы ваш ответ стоял один? – GHC

+1

уверен: вы можете распечатать перехваченные исключения, как это: попробовать: # ваших попробовать код здесь кроме исключений, как например: печати экс теперь будет печататься ошибка – Gura

1

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

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

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

1

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

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

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

Смежные вопросы