Это вопрос, над которым я размышлял довольно долгое время, но так и не нашел подходящего решения. Если я запускаю сценарий и сталкиваюсь, скажем, с IndexError, python печатает строку, местоположение и краткое описание ошибки и завершает работу. Можно ли автоматически запускать pdb при обнаружении ошибки? Я не против наличия дополнительного оператора импорта в верхней части файла или нескольких дополнительных строк кода.






Это не отладчик, но он, наверное, не менее полезен (?)
Я знаю, что слышал, как Гвидо где-то говорил об этом.
Я только что проверил python -?, И если вы используете команду -i, вы можете взаимодействовать с тем местом, где остановился ваш скрипт.
Итак, учитывая этот сценарий:
testlist = [1,2,3,4,5, 0]
prev_i = None
for i in testlist:
if not prev_i:
prev_i = i
else:
result = prev_i/i
Вы можете получить этот результат!
PS D:\> python -i debugtest.py
Traceback (most recent call last):
File "debugtest.py", line 10, in <module>
result = prev_i/i
ZeroDivisionError: integer division or modulo by zero
>>>
>>>
>>> prev_i
1
>>> i
0
>>>
Если честно, я этим не пользовался, но должен быть, кажется очень полезным.
Легкий, но часто именно то, что нужно
Не так полезно, запускается в глобальном масштабе. Не могу ковыряться в какой-то сбойной функции.
как это можно сделать, чтобы он перешел в «отладку» только в случае ошибки.
Вы можете использовать traceback.print_exc для печати трассировки исключений. Затем используйте sys.exc_info для извлечения трассировки и, наконец, вызовите pdb.post_mortem с этой трассировкой
import pdb, traceback, sys
def bombs():
a = []
print a[0]
if __name__ == '__main__':
try:
bombs()
except:
extype, value, tb = sys.exc_info()
traceback.print_exc()
pdb.post_mortem(tb)
Если вы хотите запустить интерактивную командную строку с code.interact, используя локальные значения кадра, в котором возникло исключение, вы можете сделать
import traceback, sys, code
def bombs():
a = []
print a[0]
if __name__ == '__main__':
try:
bombs()
except:
type, value, tb = sys.exc_info()
traceback.print_exc()
last_frame = lambda tb=tb: last_frame(tb.tb_next) if tb.tb_next else tb
frame = last_frame().tb_frame
ns = dict(frame.f_globals)
ns.update(frame.f_locals)
code.interact(local=ns)
первое решение дополнительно обсуждается на кулинарная книга python
почему кто-то может предпочесть codepdb, если последний, кажется, расширяет первый?
У меня такой же вопрос? Почему вы предпочитаете code?
sys.exc_info для извлечения трассировки и, наконец, вызовите pdb.post_mortem с этой трассировкой.. Вам не нужно передавать объект трассировки в pdb.post_mortem. От документы: Если обратная трассировка не указана, используется то исключение, которое в настоящее время обрабатывается (исключение должно обрабатываться, если должно использоваться значение по умолчанию).@PiotrDobrogost Хорошее замечание. Я думаю, что более полезно знать, что вы можете передать объект tb, поскольку он лучше демонстрирует API. Приятно знать, что существуют оба варианта.
Я помещаю эти фрагменты в контекстные менеджеры в свой файл util.py - pastebin.com/7rC8EsuC
Это так же хорошо, как система перезапуска Common Lisp? Допустим, вы написали "5" + num, когда хотели написать "5" + str (num), возможно ли после выполнения post_mortem исправить вашу ошибку, а затем продолжить работу, как будто ничего не произошло?
Относительно "почему вы предпочитаете код, а не pdb в командной строке?" - есть контексты, в которых интерпретатор запускается изнутри процесса, который не позволяет вам запускать отладчик как оболочку ... например. когда интерпретатор является просто частью более крупного приложения или некоторая структура управляет сложной средой, окружающей интерпретатор. В таких случаях имеет смысл сделать такой лаунчер-заглушку.
Используйте следующий модуль:
import sys
def info(type, value, tb):
if hasattr(sys, 'ps1') or not sys.stderr.isatty():
# we are in interactive mode or we don't have a tty-like
# device, so we call the default hook
sys.__excepthook__(type, value, tb)
else:
import traceback, pdb
# we are NOT in interactive mode, print the exception...
traceback.print_exception(type, value, tb)
print
# ...then start the debugger in post-mortem mode.
# pdb.pm() # deprecated
pdb.post_mortem(tb) # more "modern"
sys.excepthook = info
Назовите его debug (или как хотите) и поместите где-нибудь на своем пути к Python.
Теперь, в начале вашего скрипта, просто добавьте import debug.
Это должен быть принятый ответ - он не требует какой-либо модификации существующего кода или обертывания всего в try-catch, что является просто уродливым ИМО.
Это выглядит великолепно, но обратите внимание, что некоторые фреймворки (например, flask) уже устанавливают sys.excepthook. У них часто есть свои собственные, даже лучшие подходы, такие как werkzeug, но см. Также python - Flask и sys \ .excepthook - qaru
python -m pdb -c continue myscript.py
Если вы не предоставили флаг -c continue, вам нужно будет ввести «c» (для продолжения), когда начнется выполнение. Затем он дойдет до точки ошибки и предоставит вам контроль над ней. Как и упомянутый eqzx, этот флаг является новым дополнением в python 3.2, поэтому для более ранних версий Python требуется ввод «c» (см. https://docs.python.org/3/library/pdb.html).
Вау, спасибо! Если бы теперь этого первоначального вызова PDB можно было бы избежать, все было бы идеально. Есть идеи?
Спасибо за упоминание «введите 'c'» - я обычно вводил «r» (для «бега»), привык к этому с gdb; и когда вы вводите 'r' в pdb, программа действительно запускается, но НЕ останавливается (и не генерирует обратную трассировку) при ошибке; меня озадачили, пока я не прочитал это. Ваше здоровье!
Я попробовал ваш метод. Но, похоже, он не предлагает никакого реального контроля, такого как проверка переменных во время ошибки. Единственный вариант, который он предлагает, - это перезапустить выполнение.
Vineet, он запустит вас с включенным отладчиком, поэтому введите «cont», и он будет работать до тех пор, пока не будет обнаружена ошибка. Оттуда вы можете проверять переменные и т.д., как и в любом другом сеансе pdb.
Пожалуйста, OP, примите это как ответ. Это самый полезный, и я потратил 5 минут на чтение других, пока не выбрал этот ... это должно быть первым!
То же самое работает и с ipdb; и, конечно же, после скрипта можно добавить аргументы!
Это ответ, который я искал. Принятый ответ требует добавления кода только для запуска сеанса отладки, что очень неудобно.
ОП, пожалуйста, не принимайте это как ответ. Например, это не работает для KeyError. Он снова запускает сеанс отладчика в начале сценария, а не в строке с ошибкой. Выбранный ответ (тип, значение, tb = sys.exc_info () + traceback.print_exc () + pdb.post_mortem (tb)) является правильным.
@tutuDajuju, как заставить это работать с ipdb? Я попытался просто заменить pdb в приведенной выше команде на ipdb, но это дало мне ошибку, в которой говорилось, что «-c не существует».
@vivek кажется, что это был исправлено недавно, но еще не выпущен для pypi.
Это не работает с Python 2.7. docs.python.org/3/library/pdb.html: «Новое в версии 3.2: pdb.py теперь принимает параметр -c, который выполняет команды»
@eqzx Остальная часть ответа остается в силе. Нам нужно только нажать «c» после выполнения ... в остальном все в порядке!
и сделайте pip install pdbpp перед использованием выше, для лучшего пользовательского интерфейса.
@eqzx одно из решений, позволяющих избежать наличия флага -c в Python 2.7, - это (echo c && cat) | python -pdb script.py.
очень удобно: псевдоним pd = 'python3 -m pdb -c continue'
Вы можете поместить эту строку в свой код:
import pdb ; pdb.set_trace()
Подробнее: Запустить отладчик python в любой строке
Это останавливает код и запускает отладчик в строке, в которой вы поместили эту команду, а не в строке, где произошло исключение.
Ипайтон имеет команду для переключения этого поведения: % pdb. Он делает именно то, что вы описали, может быть, даже немного больше (дает вам более информативные обратные трассировки с подсветкой синтаксиса и автозавершением кода). Однозначно стоит попробовать!
И это единственный разумный ответ на этот вопрос.
Документировано на ipython.readthedocs.io/en/stable/interactive/…
Обратите внимание, что - как также отмечено в связанных документах @matthiash - %debug позволяет открыть отладчик после, обнаружив ошибку. Я часто предпочитаю это %pdb. (Компромисс заключается в простом вводе q каждый раз, когда вы не хотите отлаживать ошибку, по сравнению с вводом %debug каждый раз, когда вы делать хотите отладить ошибку.)
Также обратите внимание, что установка c.InteractiveShell.pdb = True в ipython_config.py автоматически включает %pdb для каждой сессии.
Это правильный ответ.
Поместите точку останова внутри конструктора самого верхнего класса исключения в иерархии, и в большинстве случаев вы увидите, где возникла ошибка.
Установка точки останова означает все, что вы хотите: вы можете использовать IDE, или pdb.set_trace, или что-то еще.
Чтобы запустить его без ввода c в начале, используйте:
python -m pdb -c c <script name>
Pdb имеет свои собственные аргументы командной строки: -c c будет выполнять команду c (ontinue) в начале выполнения, и программа будет работать без прерывания до появления ошибки.
IPython упрощает это в командной строке:
python myscript.py arg1 arg2
можно переписать на
ipython --pdb myscript.py -- arg1 arg2
Или, аналогично, при вызове модуля:
python -m mymodule arg1 arg2
можно переписать на
ipython --pdb -m mymodule -- arg1 arg2
Обратите внимание на то, что -- не позволяет IPython считывать аргументы сценария как свои собственные.
Это также дает преимущество вызова расширенного отладчика IPython (ipdb) вместо pdb.
Если вы используете модуль:
python -m mymodule
И теперь вы хотите ввести pdb при возникновении исключения, сделайте следующее:
PYTHONPATH = "." python -m pdb -c c mymodule/__main__.py
(или продлевать ваш PYTHONPATH). PYTHONPATH нужен для того, чтобы модуль был найден в пути, поскольку вы сейчас запускаете модуль pdb.
Если вы используете среду IPython, вы можете просто использовать% debug, и оболочка вернет вас к нарушающей строке со средой ipdb для проверок и т. д. Другой вариант, как указано выше, - использовать iPython magic% pdb, который эффективно выполняет тоже самое.
Обратите внимание, что если ошибка возникла в функции модуля, вы можете перемещаться по фреймам с помощью команд up и down, чтобы вернуться к строке вашего кода, которая сгенерировала ошибку.
python -m pdb script.py в python2.7 нажмите «Продолжить», чтобы запустить, и он запустится до ошибки и прервется для отладки.
Если вы используете ipython, после запуска введите %pdb
In [1]: %pdb
Automatic pdb calling has been turned ON
Привет, @jeremy, не могли бы вы изменить принятый ответ на Кэтрин Девлин ответ? Это фантастический вопрос, и принятый в настоящее время ответ Флориана Бёша великолепен, но ответ Екатерины проще, и я думаю, что посетителям было бы лучше, если бы он был показан первым. (Я удалю этот комментарий через пару дней.)