Как сохранить значения traceback/sys.exc_info() в переменной?
Я хочу сохранить имя ошибки и данные трассировки в переменной. Вот моя попытка.
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
P.S. Я знаю, что это можно легко сделать с помощью модуля traceback, но я хочу узнать об использовании объекта sys.exc_info() [2] здесь.
Ответы
Ответ 1
Вот как я это делаю:
>>> 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'
Однако вы должны взглянуть на документацию трассировки, так как вы можете найти там более подходящие методы, в зависимости от того, как вы хотите обработать свою переменную впоследствии...
Ответ 2
sys.exc_info() возвращает кортеж с тремя значениями (тип, значение, трассировка).
- Здесь тип получает тип исключения обрабатываемого Исключения
- Значение - это аргументы, которые передаются конструктору класса исключений
- traceback содержит информацию о стеке, например, где произошло исключение и т.д.
Например, в следующей программе
try:
a = 1/0
except Exception,e:
exc_tuple = sys.exc_info()
Теперь, если мы напечатаем кортеж, значения будут такими.
- Значение exc_tuple [0] будет " ZeroDivisionError"
- Значение exc_tuple [1] будет " целочисленным делением или по модулю нулем" (строка, переданная как параметр в класс исключения)
- Значение exc_tuple [2] будет " трекбэк-объект в (на некотором адресе памяти)"
Вышеприведенные данные также можно получить, просто распечатав исключение в формате строки.
print str(e)
Ответ 3
Используйте 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'
Ответ 4
Мой ответ на другой вопрос может помочь проиллюстрировать детали - со ссылками! Для консервированных строк стандартный модуль трассировки библиотеки выглядит нормально. Если вы хотите получить информацию, прочитайте источник (<python install path>/Lib/traceback.py
) для получения дополнительной информации.
Ответ 5
Объект можно использовать в качестве параметра в функции Exception.with_traceback()
:
except Exception as e:
tb = sys.exc_info()
print(e.with_traceback(tb[2]))
Ответ 6
Будьте осторожны, когда вы берете объект исключения или объект трассировки из обработчика исключений, так как это вызывает циклические ссылки, и 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 проблема с env для ноутбуков ipython или jupyter заключается в том, что в нем есть %tb
magic, который сохраняет трассировку и делает ее доступной в любой момент позже. И в результате любые locals()
во всех кадрах, участвующих в трассировке, не будут освобождены, пока ноутбук не выйдет или другое исключение не перезапишет ранее сохраненную трассировку. Это очень проблематично. Он не должен хранить трассировку без очистки своих кадров. Исправление представлено здесь.