Как сохранить значения traceback / sys.exc_info () в переменной? - PullRequest
101 голосов
/ 23 ноября 2011

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

import sys
try:
    try:
        print x
    except Exception, ex:
        raise NameError
except Exception, er:
    print "0", sys.exc_info()[0]
    print "1", sys.exc_info()[1]
    print "2", sys.exc_info()[2]

Вывод:

0 <type 'exceptions.NameError'>
1 
2 <traceback object at 0xbd5fc8>

Желаемый вывод:

0 NameError
1
2 Traceback (most recent call last):
  File "exception.py", line 6, in <module>
    raise NameError

PSЯ знаю, что это легко сделать с помощью модуля traceback, но я хочу знать, как использовать объект sys.exc_info () [2] здесь.

Ответы [ 5 ]

143 голосов
/ 23 ноября 2011

Вот как я это делаю:

>>> import traceback
>>> try:
...   int('k')
... except:
...   var = traceback.format_exc()
... 
>>> print var
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
ValueError: invalid literal for int() with base 10: 'k'

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

19 голосов
/ 07 июня 2015

sys.exc_info () возвращает кортеж с тремя значениями (тип, значение, обратная связь).

  1. Здесь тип получает тип исключения для обрабатываемого исключения.
  2. значение - это аргументы, которые передаются в конструктор класса исключения

Например, в следующей программе

try:

    a = 1/0

except Exception,e:

    exc_tuple = sys.exc_info()

Теперь, если мы распечатаем кортеж, значения будут следующими.

  1. exc_tuple [0] будет равно " ZeroDivisionError "
  2. exc_tuple [1] будет равно " целочисленное деление или по модулю на ноль"(Строка, переданная в качестве параметра в класс исключений)
  3. exc_tuple [2] будет иметь значение" объект отслеживания в (некоторый адрес памяти)"

Вышеуказанные детали также можно получить, просто распечатав исключение в строковом формате.

print str(e)
16 голосов
/ 09 августа 2014

Используйте traceback.extract_stack(), если вам нужен удобный доступ к именам модулей и функций и номерам строк.

Используйте ''.join(traceback.format_stack()), если вам нужна строка, похожая на вывод traceback.print_stack().

Обратите внимание, что даже с ''.join() вы получите многострочную строку, поскольку элементы format_stack() содержат \n.См. Вывод ниже.

Не забудьте import traceback.

Вот вывод из traceback.extract_stack().Для удобства чтения добавлено форматирование.

>>> traceback.extract_stack()
[
   ('<string>', 1, '<module>', None),
   ('C:\\Python\\lib\\idlelib\\run.py', 126, 'main', 'ret = method(*args, **kwargs)'),
   ('C:\\Python\\lib\\idlelib\\run.py', 353, 'runcode', 'exec(code, self.locals)'),
   ('<pyshell#1>', 1, '<module>', None)
]

Вот вывод из ''.join(traceback.format_stack()).Для удобства чтения добавлено форматирование.

>>> ''.join(traceback.format_stack())
'  File "<string>", line 1, in <module>\n
   File "C:\\Python\\lib\\idlelib\\run.py", line 126, in main\n
       ret = method(*args, **kwargs)\n
   File "C:\\Python\\lib\\idlelib\\run.py", line 353, in runcode\n
       exec(code, self.locals)\n  File "<pyshell#2>", line 1, in <module>\n'
1 голос
/ 21 января 2019

Будьте осторожны, когда вы берете объект исключения или объект трассировки из обработчика исключений, так как это вызывает циклические ссылки и gc.collect() не удастся собрать.Это, как представляется, представляет собой особую проблему в среде ноутбука ipython / jupyter, где объект трассировки не очищается в нужное время и даже явный вызов gc.collect() в разделе finally ничего не делает.И это огромная проблема, если у вас есть огромные объекты, которые из-за этого не восстанавливают свою память (например, CUDA из-за нехватки памяти, когда без этого решения требуется полный перезапуск ядра для восстановления).

В общем, если вы хотите сохранить объект трассировки, вам нужно очистить его от ссылок на locals(), например, так:

import sys, traceback, gc
type, val, tb = None, None, None
try:
    myfunc()
except:
    type, val, tb = sys.exc_info()
    traceback.clear_frames(tb)
# some cleanup code
gc.collect()
# and then use the tb:
if tb:
    raise type(val).with_traceback(tb)

В случае с блокнотом Jupyter, вы должны сделать это в самый раз.минимум в обработчике исключений:

try:
    myfunc()
except:
    type, val, tb = sys.exc_info()
    traceback.clear_frames(tb)
    raise type(val).with_traceback(tb)
finally:
    # cleanup code in here
    gc.collect()

Протестировано с python 3.7.

ps проблема с enpy для ipython или jupyter notebook заключается в том, что он обладает магией %tb, которая сохраняет трассировку и делаетдоступны в любой момент позже.И в результате любой locals() во всех кадрах, участвующих в трассировке, не будет освобожден, пока ноутбук не выйдет или другое исключение не перезапишет ранее сохраненную трассировку.Это очень проблематично.Он не должен хранить трассировку без очистки своих кадров.Исправление отправлено здесь .

0 голосов
/ 21 января 2019

Объект можно использовать в качестве параметра в функции Exception.with_traceback():

except Exception as e:
    tb = sys.exc_info()
    print(e.with_traceback(tb[2]))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...