如何逐步完成Python代码以帮助调试问题?

时间:2011-02-08 03:21:43

标签: python debugging

在Java / C#中,您可以轻松地逐步执行代码以跟踪可能出错的内容,而IDE会使此过程非常用户友好。

你能以类似的方式追踪python代码吗?

15 个答案:

答案 0 :(得分:204)

是的!有一个名为pdb的Python调试器只是为了做到这一点!

您可以使用pdbpdb myscript.py通过python -m pdb myscript.py启动Python程序。

您可以发布一些命令,这些命令记录在pdb页面上。

要记住的一些有用的是:

  • b:设置断点
  • c:继续调试,直到遇到断点
  • s:单步执行代码
  • n:转到下一行代码
  • l:列出当前文件的源代码(默认值:11行,包括正在执行的行)
  • u:向上导航堆栈框架
  • d:向下导航堆栈框架
  • p:在当前上下文中打印表达式的值

如果您不想使用命令行调试器,某些IDE(如Pydev)会有一个GUI调试器。

答案 1 :(得分:42)

使用Python Interactive Debugger'pdb'

第一步是让Python解释器进入调试模式。

:一种。从命令行

最直接的方式,从命令行运行,python解释器

$ python -m pdb scriptName.py
> .../pdb_script.py(7)<module>()
-> """
(Pdb)

<强> B中。在口译员

开发早期版本的模块并进行更多迭代实验。

$ python
Python 2.7 (r27:82508, Jul  3 2010, 21:12:11)
[GCC 4.0.1 (Apple Inc. build 5493)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import pdb_script
>>> import pdb
>>> pdb.run('pdb_script.MyObj(5).go()')
> <string>(1)<module>()
(Pdb)

<强>℃。来自您的计划

对于一个大项目和长期运行的模块,可以从程序内部启动调试 导入pdb set_trace() 像这样:

#!/usr/bin/env python
# encoding: utf-8
#

import pdb

class MyObj(object):
    count = 5
    def __init__(self):
        self.count= 9

    def go(self):
        for i in range(self.count):
            pdb.set_trace()
            print i
        return

if __name__ == '__main__':
    MyObj(5).go()

逐步调试以进入更内部的

  1. 执行下一个声明... “n”(下一个)

  2. 使用 ENTER 重复上一个调试命令

  3. 全部退出...... “q”(退出)

  4. 使用“p”(打印)

    打印变量值....

    a) p a

  5. 关闭(Pdb)提示符... “c”(继续)

  6. 通过“l”(列表)

  7. 查看您的位置...
  8. 进入子程序... “s”(步入)

  9. 继续...但只是到当前子程序的结尾......用“r”(返回)

  10. 分配新值

    a)!b =“B”

  11. 设置断点

    a)打破亚麻布

    b) break functionname

    c) break filename:linenumber

  12. 临时断点

    a) tbreak linenumber

  13. 条件断点

    a)打破亚麻,条件

  14. 注意:**所有这些命令都应该从** pdb

    执行

    有关深入的知识,请参阅: -

    https://pymotw.com/2/pdb/

    https://pythonconquerstheuniverse.wordpress.com/2009/09/10/debugging-in-python/

答案 2 :(得分:34)

python中有一个名为'pdb'的模块。在你的python脚本的顶部你做

import pdb
pdb.set_trace()

您将进入调试模式。您可以使用“s”步骤,“n”跟随下一行,类似于使用“gdb”调试器所做的操作。

答案 3 :(得分:10)

从Python 3.7开始,您可以使用breakpoint()内置函数进入调试器:

foo()
breakpoint()  # drop into the debugger at this point
bar()

默认情况下,breakpoint()将导入pdb并调用pdb.set_trace()。但是,您可以通过sys.breakpointhook()和使用环境变量PYTHONBREAKPOINT来控制调试行为。

有关更多信息,请参见PEP 553

答案 4 :(得分:6)

ipdb(IPython调试器)

ipdb向pdb添加了IPython功能,提供了以下巨大改进:

  • 选项卡完成
  • 显示更多上下文行
  • 语法突出显示

与pdg一样,与GDB相比,ipdb仍远远不够完善和完全初级,但与pdb相比已经有了很大的改进。

用法类似于pdb,只需使用以下命令进行安装:

python3 -m pip install --user ipdb

,然后添加到您要从中逐步调试的行:

__import__('ipdb').set_trace(context=21)

您可能想从编辑器中为其添加快捷方式,例如对于Vim snipmate,我有:

snippet ipd
    __import__('ipdb').set_trace(context=21)

所以我只能输入ipd<tab>,它会扩展到断点。然后dd删除它很容易,因为所有内容都包含在一行中。

context=21增加了上下文行的数量,如How can I make ipdb show more lines of context while debugging?

所述。

或者,您也可以从头开始调试程序,

ipdb3 main.py

但是您通常不想这样做,因为:

  • 在Python读取这些行时,您将必须遍历所有函数和类定义
  • 我不知道如何在不破坏ipdb的情况下设置上下文大小。进行修补以允许它:https://github.com/gotcha/ipdb/pull/155

或者,如在原始pdb 3.2+中一样,您可以从命令行设置一些断点:

ipdb3 -c 'b 12' -c 'b myfunc' ~/test/a.py

尽管-c c由于某些原因而损坏:https://github.com/gotcha/ipdb/issues/156

python -m module调试已在以下位置进行:How to debug a Python module run with python -m from the command line?,由于Python 3.7可以通过以下方式完成:

python -m pdb -m my_module

与GDB相比,pdb和ipdb都严重缺少一些功能:

ipdb的烦恼:

已在Ubuntu 16.04,ipdb == 0.11,Python 3.5.2中进行了测试。

答案 5 :(得分:3)

如果你来自Java / C#背景,我猜你最好的选择是EclipsePydev一起使用。这为您提供了一个内置调试器的功能齐全的IDE。我也将它与django一起使用。

答案 6 :(得分:2)

如果您想要一个带有集成调试器的IDE,请尝试PyScripter

答案 7 :(得分:1)

也可以通过编程方式步进和跟踪python代码(并且很简单!)。查看sys.settrace()文档以获取更多详细信息。另外here是一个帮助您入门的教程。

答案 8 :(得分:1)

答案 9 :(得分:1)

答案 10 :(得分:1)

Python Tutor是在线单步调试器。您可以将代码放在edit页面上,然后单击“可视化执行”以开始运行。

答案 11 :(得分:1)

让我们来看看breakpoint()在3.7+中可以为您做什么。

我已经通过

安装了ipdbpdbpp,它们都是增强的调试器。
pip install pdbpp
pip install ipdb

我的测试脚本,实际上并没做什么,只调用breakpoint()

#test_188_breakpoint.py
myvars=dict(foo="bar")
print("before breakpoint()")
breakpoint()   # ?
print(f"after breakpoint myvars={myvars}")


breakpoint()链接到PYTHONBREAKPOINT环境变量。

情况1:禁用breakpoint()

您可以照常通过bash设置变量

export PYTHONBREAKPOINT=0

这会关闭不执行任何操作的breakpoint()(只要您没有修改sys.breakpointhook(),这不在此答案的范围之内)。

这是程序运行的样子:

(venv38) myuser@explore$ export PYTHONBREAKPOINT=0
(venv38) myuser@explore$ python test_188_breakpoint.py
before breakpoint()
after breakpoint myvars={'foo': 'bar'}
(venv38) myuser@explore$

没有停止,因为我禁用了断点。 pdb.set_trace()无法做的事

情况2:使用默认的pdb行为:

现在,让我们取消设置PYTHONBREAKPOINT,这将使我们回到正常的启用断点行为(仅当0处于空状态时才被禁用)。

(venv38) myuser@explore$ unset PYTHONBREAKPOINT
(venv38) myuser@explore$ python test_188_breakpoint.py
before breakpoint()
[0] > /Users/myuser/kds2/wk/explore/test_188_breakpoint.py(6)<module>()
-> print(f"after breakpoint myvars={myvars}")
(Pdb++) print("pdbpp replaces pdb because it was installed")
pdbpp replaces pdb because it was installed
(Pdb++) c
after breakpoint myvars={'foo': 'bar'}

它停止了,但是我实际上得到了pdbpp,因为它在安装时完全取代了pdb。如果我放心使用pdbpp,我会恢复为正常的pdb

注意:标准的pdb.set_trace()仍然会让我pdbpp

案例3:调用自定义调试器

但是我们叫ipdb。这次,我们可以使用bash仅针对此一条命令设置它,而不是设置环境变量。

(venv38) myuser@explore$ PYTHONBREAKPOINT=ipdb.set_trace py test_188_breakpoint.py
before breakpoint()
> /Users/myuser/kds2/wk/explore/test_188_breakpoint.py(6)<module>()
      5 breakpoint()
----> 6 print(f"after breakpoint myvars={myvars}")
      7

ipdb> print("and now I invoked ipdb instead")
and now I invoked ipdb instead
ipdb> c
after breakpoint myvars={'foo': 'bar'}

从本质上讲,它在查看$ PYTHONBREAKPOINT时的作用:

from ipdb import set_trace  # function imported on the right-most `.`
set_trace()

再次,比普通的旧pdb.set_trace()聪明得多

在实践中?我可能会选择调试器。

说我一直想要ipdb,我会:

  • export通过.profile或类似的版本。
  • 逐个命令禁用,而不修改常规值

示例(pytest和调试器经常使不快乐的夫妻成婚)

(venv38) myuser@explore$ export PYTHONBREAKPOINT=ipdb.set_trace
(venv38) myuser@explore$ echo $PYTHONBREAKPOINT
ipdb.set_trace
(venv38) myuser@explore$ PYTHONBREAKPOINT=0 pytest test_188_breakpoint.py
=================================== test session starts ====================================
platform darwin -- Python 3.8.6, pytest-5.1.2, py-1.9.0, pluggy-0.13.1
rootdir: /Users/myuser/kds2/wk/explore
plugins: celery-4.4.7, cov-2.10.0
collected 0 items

================================== no tests ran in 0.03s ===================================
(venv38) myuser@explore$ echo $PYTHONBREAKPOINT
ipdb.set_trace

p.s。

我在bash下使用macos,任何posix shell的行为基本相同。 Windows,无论是Powershell还是DOS,都可能具有不同的功能,尤其是在PYTHONBREAKPOINT=<some value> <some command>周围,只能为一个命令设置环境变量。

答案 12 :(得分:1)

如果您想使用 IDE,PyCharm 有一个不错的替代方案:VScode

  1. 安装 VScode
  2. 添加 Python 扩展(如果它不存在)
  3. 使用 Python 代码创建文件 mymodule.py
  4. 点击 mymodule.py 处的行号以设置断点
  5. 点击 F5 并选择 Debug Python file

它将在断点处停止,您可以在选项卡 VARIABLES(通常在左侧)或通过单击 Debug Console(通常在在您的 Terminal 旁边的底部):

enter image description here

答案 13 :(得分:0)

PyCharm是适用于Python的IDE,其中包括调试器。观看此YouTube视频,以获取有关使用PyCharm调试器逐步执行代码的介绍。

PyCharm Tutorial - Debug python code using PyCharm

注意:这并不是要背书或评论。 PyCharm是一种需要付费的商业产品,但该公司确实向学生和教师提供了免费许可,以及一个“轻巧”的社区版本,该版本是免费且开源的。

Screenshot

答案 14 :(得分:0)

如今存在breakpoint()方法,它取代了import pdb; pdb.set_trace()

它也有several new features,例如可能的环境变量。