Некоторые другие ответы уже указали на модуль трассировки .
Обратите внимание, что print_exc
в некоторых случаях вы не получите того, чего ожидаете. В Python 2.x:
import traceback
try:
raise TypeError("Oups!")
except Exception, err:
try:
raise TypeError("Again !?!")
except:
pass
traceback.print_exc()
... отобразит трассировку последнего исключения:
Traceback (most recent call last):
File "e.py", line 7, in <module>
raise TypeError("Again !?!")
TypeError: Again !?!
Если вам действительно нужен доступ к исходной трассировке, одним из решений является кэширование информации об исключении, возвращенной из exc_info
локальной переменной, и ее отображение с помощью print_exception
:
import traceback
import sys
try:
raise TypeError("Oups!")
except Exception, err:
try:
exc_info = sys.exc_info()
# do you usefull stuff here
# (potentially raising an exception)
try:
raise TypeError("Again !?!")
except:
pass
# end of useful stuff
finally:
# Display the *original* exception
traceback.print_exception(*exc_info)
del exc_info
Производство:
Traceback (most recent call last):
File "t.py", line 6, in <module>
raise TypeError("Oups!")
TypeError: Oups!
Хотя есть несколько подводных камней с этим:
Из документа sys_info
:
Присвоение возвращаемого значения traceback локальной переменной в функции, которая обрабатывает исключение, вызовет циклическую ссылку . Это предотвратит сбор мусора, на который ссылается локальная переменная в той же функции или трассировка. [...] Если вам нужна трассировка, обязательно удалите ее после использования (лучше всего делать с помощью оператора try ... finally)
но из того же документа:
Начиная с Python 2.2, такие циклы автоматически восстанавливаются, когда сборка мусора включена, и они становятся недоступными, но остается более эффективным избегать создания циклов.
С другой стороны, предоставляя вам доступ к трассировке, связанной с исключением, Python 3 дает менее удивительный результат:
import traceback
try:
raise TypeError("Oups!")
except Exception as err:
try:
raise TypeError("Again !?!")
except:
pass
traceback.print_tb(err.__traceback__)
... отобразит:
File "e3.py", line 4, in <module>
raise TypeError("Oups!")
print(sys.exc_info()[0]
отпечатки<class 'Exception'>
.Если вы отлаживаете и хотите видеть текущую трассировку стека, вы можете просто вызвать:
traceback.print_stack()
Нет необходимости вручную вызывать исключение, чтобы просто перехватить его.
источник
Если вы не хотите останавливать свою программу из-за ошибки, вам нужно обработать эту ошибку с помощью try / кроме:
Для извлечения полной трассировки мы будем использовать
traceback
модуль из стандартной библиотеки:И создать довольно сложную трассировку стека, чтобы продемонстрировать, что мы получаем полную трассировку стека:
печать
Чтобы распечатать полную трассировку, используйте
traceback.print_exc
метод:Какие отпечатки:
Лучше, чем печать, регистрация:
Однако лучше всего настроить регистратор для вашего модуля. Он будет знать имя модуля и сможет изменять уровни (среди других атрибутов, таких как обработчики)
В этом случае вам понадобится
logger.exception
функция вместо:Какие журналы:
Или, возможно, вам просто нужна строка, в этом случае вам понадобится
traceback.format_exc
функция:Какие журналы:
Вывод
И для всех трех опций мы видим, что получаем тот же результат, что и при появлении ошибки:
источник
traceback.print_exc()
возвращает только последний вызов: как вам удастся вернуть несколько уровней стека (и, возможно, все уровни?)raise
цепочку голых или исключений, или вы скрываете первоначальную трассировку? см. stackoverflow.com/questions/2052390/…Во- первых, не используйте
print
s для протоколирования, там нестабильна, проверенная и хорошо продуманный модуль STDLIB , чтобы сделать это:logging
. Вы определенно должны использовать это вместо этого.Во-вторых, не поддавайтесь соблазну создавать беспорядок с не связанными инструментами, когда есть нативный и простой подход. Вот:
Вот и все. Вы сделали сейчас.
Объяснение для всех, кто интересуется, как все работает под капотом
Что
log.exception
на самом деле делает, так это просто вызовlog.error
(то есть регистрирует событие с уровнемERROR
) и затем вывод трассировки.Почему лучше?
Ну, вот некоторые соображения:
Почему никто не должен использовать
traceback
или вызывать регистратор сexc_info=True
или грязные рукиsys.exc_info
?Ну просто потому что! Все они существуют для разных целей. Например,
traceback.print_exc
выходные данные немного отличаются от обратных трассировок, производимых самим интерпретатором. Если вы используете его, вы запутаете любого, кто читает ваши журналы, они будут бить себя против них.Переход
exc_info=True
на входящие звонки просто неуместен. Но это полезно при отлове восстанавливаемых ошибок, и вы хотите регистрировать их (используя, например,INFO
уровень) также с помощью обратных трассировок, потому чтоlog.exception
создает журналы только одного уровня -ERROR
.И вам определенно следует избегать возиться с
sys.exc_info
как можно большим количеством. Это просто не публичный интерфейс, а внутренний - вы можете использовать его, если точно знаете, что делаете. Он не предназначен только для печати исключений.источник
logging.exception()
. Нет необходимости создавать экземпляр журнала, если у вас нет особых требований.В дополнение к ответу @Aaron Hall, если вы регистрируетесь, но не хотите использовать
logging.exception()
(так как он регистрирует на уровне ERROR), вы можете использовать более низкий уровень и пройтиexc_info=True
. напримеристочник
Чтобы получить точную трассировку стека в виде строки, которая была бы вызвана, если бы не было попытки / кроме того, чтобы перешагнуть через нее, просто поместите ее в блок исключения, который перехватывает ошибочное исключение.
Вот как это использовать (при условии, что
flaky_func
оно определено иlog
вызывает вашу любимую систему регистрации):Это хорошая идея, чтобы ловить и повторно поднимать
KeyboardInterrupt
s, так что вы все равно можете убить программу, используя Ctrl-C. Ведение журнала выходит за рамки вопроса, но хорошим вариантом является ведение журнала . Документация для модулей sys и traceback .источник
desired_trace = traceback.format_exc()
. Передачаsys.exc_info()
в качестве аргумента никогда не была правильной вещью, но игнорируется в Python 2, но не в Python 3 (в любом случае, 3.6.4).KeyboardInterrupt
не происходит (прямо или косвенно) отException
. (Оба получены изBaseException
.) Это означает,except Exception:
что никогда не поймает aKeyboardInterrupt
, и, следовательно,except KeyboardInterrupt: raise
совершенно не нужно.traceback.format_exc(sys.exc_info())
у меня не работает с питоном 3.6.10Вам нужно будет поместить попытку / исключение в самую внутреннюю петлю, где может возникнуть ошибка, т.е.
... и так далее
Другими словами, вам нужно будет обернуть операторы, которые могут потерпеть неудачу в try /, за исключением как можно более конкретных, в максимально возможной внутренней петле.
источник
Замечание по поводу комментариев этого ответа :
print(traceback.format_exc())
делает для меня лучшую работу, чемtraceback.print_exc()
. Чтоhello
касается последнего, то иногда странным образом «смешивается» с текстом трассировки, например, если оба хотят одновременно писать в stdout или stderr, производя странный вывод (по крайней мере, при сборке из текстового редактора и просмотре вывода в Панель «Результаты сборки»).Поэтому я использую:
источник
Я не вижу это упомянутое ни в одном из других ответов. Если вы передаете объект Exception по любой причине ...
В Python 3.5+ вы можете получить трассировку от объекта Exception, используя traceback.TracebackException.from_exception () . Например:
Однако приведенный выше код приводит к:
Это всего лишь два уровня стека, в отличие от того, что было бы напечатано на экране, если бы исключение было поднято
stack_lvl_2()
и не было перехвачено (раскомментируйте# raise
строку).Насколько я понимаю, это связано с тем, что
stack_lvl_3()
в данном случае исключение записывает только текущий уровень стека при его повышении . Когда он проходит обратно через стек, к нему добавляется больше уровней__traceback__
. Но мы перехватили егоstack_lvl_2()
, то есть все, что нужно было записать, это уровни 3 и 2. Чтобы получить полную трассировку, напечатанную на stdout, нам нужно поймать ее на самом высоком (самом низком?) Уровне:Что приводит к:
Обратите внимание, что печать стека отличается, первая и последняя строки отсутствуют. Потому что это другое
format()
.Перехват исключения как можно дальше от того места, где оно было вызвано, упрощает код, а также дает больше информации.
источник
Получить полную трассировку в виде строки из объекта исключения с
traceback.format_exception
Если у вас есть только объект исключения, вы можете получить обратную трассировку в виде строки из любой точки кода в Python 3 с помощью:
Полный пример:
Вывод:
Документация: https://docs.python.org/3.7/library/traceback.html#traceback.format_exception
См. Также: извлечение информации трассировки из объекта исключения.
Протестировано в Python 3.7.3.
источник
Вы хотите модуль трассировки . Это позволит вам печатать дампы стека, как это обычно делает Python. В частности, функция print_last напечатает последнее исключение и трассировку стека.
источник
Если у вас уже есть объект Error, и вы хотите напечатать все это, вам нужно сделать этот слегка неловкий вызов:
Это верно,
print_exception
занимает три позиционных аргумента: тип исключения, фактический объект исключения и собственное внутреннее свойство трассировки исключения.В python 3.5 или более поздних версиях
type(err)
является необязательным ... но это позиционный аргумент, поэтому вам все равно придется явно передать None вместо него.Я понятия не имею, почему все это не просто
traceback.print_exception(err)
. Почему вы когда-нибудь захотите распечатать ошибку вместе с трассировкой, отличной от той, которая принадлежит этой ошибке, мне не понятно.источник