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

Bla*_*man 163 python debugging

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

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

小智 234

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

您可以pdb使用pdb myscript.py或启动Python程序python -m pdb myscript.py.

然后可以发布一些命令,这些命令在pdb页面上记录.

一些有用的要记住的是:

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

如果您不想使用命令行调试器,某些像Pydev这样的IDE 会有一个GUI调试器.

  • 哇,我简直不敢相信我很难找到linux/ubuntu的图形pdb.我错过了什么吗?我可能不得不考虑为它制作一个SublimeText插件. (8认同)
  • PyCharm作为图形化调试器非常好,它的Community Edition是免费的! (3认同)
  • `pdb` 不是命令行工具。要使用它,请使用“python -m pdb your_script.py”。 (3认同)

akD*_*akD 45

使用Python Interactive Debugger'pdb'

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

A.从命令行

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

$ python -m pdb scriptName.py
> .../pdb_script.py(7)<module>()
-> """
(Pdb)
Run Code Online (Sandbox Code Playgroud)

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)
Run Code Online (Sandbox Code Playgroud)

C.来自您的计划

对于一个大项目和长时间运行的模块,可以使用import pdbset_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()
Run Code Online (Sandbox Code Playgroud)

逐步调试以进入更内部

  1. 执行下一个语句...用"n"(下一个)

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

  3. 全部退出...用"q"(退出)

  4. 打印变量值...用"p"(打印)

    a) pa

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

  6. 看看你在哪里......用"l"(列表)

  7. 步入子程序......用"s"(步入)

  8. 继续...但只是到当前子程序结束...用"r"(返回)

  9. 分配新值

    a) !b ="B"

  10. 设置断点

    a) 打破亚麻布

    b) 中断functionname

    c) break filename:linenumber

  11. 临时断点

    a) tbreak linenumber

  12. 条件断点

    a) 打破亚麻,状况

注意:**所有这些命令都应该从**pdb执行

如需深入了解,请参阅: -

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

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


Sen*_*ran 37

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

import pdb
pdb.set_trace()
Run Code Online (Sandbox Code Playgroud)

然后你将进入调试模式.您可以使用's'来步骤,'n'跟随下一行,类似于您对'gdb'调试器所做的操作.


Eug*_*ash 15

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

foo()
breakpoint()  # drop into the debugger at this point
bar()
Run Code Online (Sandbox Code Playgroud)

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

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

  • 当我看到“断点”时,我很兴奋。但是后来我了解到它本质上只是`import pdb;的快捷方式;pdb.set_trace()` 这让我很伤心。Python 开发人员:请专注于改进 PDB 的基本 GDB 功能,例如上下文行、持久命令历史记录和选项卡自动完成:-) (2认同)
  • @CiroSantilliПутлерКапут六四事 不是真的。默认情况下,它指向“pdb”。通过适当的标志,它可以加载其他调试器。像“ipdb”(例如:“PYTHONBREAKPOINT=ipdb.set_trace”)或其他更高级的调试器。 (2认同)

tyr*_*rex 10

VS代码

如果您想使用 IDE,这是 PyCharm 的一个很好的替代品。

  1. 安装VSCode
  2. 安装Python 扩展(如果尚未安装)
  3. 例如,mymodule.py使用Python代码创建一个文件
  4. 要设置断点,请将鼠标悬停在行号上并单击红点,或按F9
  5. 点击F5开始调试并选择Python File

它将在断点处停止,您可以执行常规调试操作,例如检查变量的值,可以在“变量”选项卡通常位于左侧)或单击“调试控制台” (通常位于“终端”旁边的底部):

VSCode 的屏幕截图显示调试期间的调试控制台

此屏幕截图显示了VSCodium

更多信息


Cir*_*四事件 9

ipdb(IPython调试器)

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

  • 制表符完成
  • 显示更多上下文行
  • 语法高亮

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

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

python3 -m pip install --user ipdb
Run Code Online (Sandbox Code Playgroud)

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

__import__('ipdb').set_trace(context=21)
Run Code Online (Sandbox Code Playgroud)

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

snippet ipd
    __import__('ipdb').set_trace(context=21)
Run Code Online (Sandbox Code Playgroud)

这样我就可以输入,ipd<tab>并且它会扩展到断点。dd由于所有内容都包含在一行中,因此删除它很容易。

context=21增加了上下文行的数量,如下所述:在调试时如何使ipdb显示更多上下文行?

另外,您也可以从头开始调试程序:

ipdb3 main.py
Run Code Online (Sandbox Code Playgroud)

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

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

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

ipdb3 -c 'b 12' -c 'b myfunc' ~/test/a.py
Run Code Online (Sandbox Code Playgroud)

虽然-c c由于某种原因而损坏了:https : //github.com/gotcha/ipdb/issues/156

python -m module在以下位置询问了调试如何从命令行调试使用python -m运行的Python模块?由于Python 3.7可以通过以下方式完成:

python -m pdb -m my_module
Run Code Online (Sandbox Code Playgroud)

与GDB相比,pdb和ipdb严重缺少的功能:

ipdb的烦恼:

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


joh*_*ken 6

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

它还具有几个新功能,例如可能的环境变量。


wja*_*rea 5

Python Tutor是一款面向新手的在线单步调试器。您可以在编辑页面输入代码,然后单击“可视化执行”开始运行。

除其他外,它支持:

但是它也不支持很多东西,例如:

  • 读/写文件 - 使用io.StringIOio.BytesIO代替:演示
  • 代码过大、运行时间过长或定义了过多的变量或对象
  • 命令行参数
  • 许多标准库模块,如 argparse、csv、enum、html、os、struct、weakref...


JL *_*ret 5

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

我已经安装了ipdbpdbpp,它们都是增强的调试器,通过

pip install pdbpp
pip install ipdb
Run Code Online (Sandbox Code Playgroud)

我的测试脚本实际上没有做太多事情,只是调用breakpoint().

#test_188_breakpoint.py
myvars=dict(foo="bar")
print("before breakpoint()")
breakpoint()   # 
print(f"after breakpoint myvars={myvars}")
Run Code Online (Sandbox Code Playgroud)

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

情况 1:禁用断点()

bash您可以像往常一样通过设置变量

export PYTHONBREAKPOINT=0

这将关闭断点(),它不执行任何操作(只要您没有修改,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$
Run Code Online (Sandbox Code Playgroud)

没有停止,因为我禁用了断点。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'}
Run Code Online (Sandbox Code Playgroud)

它停止了,但我实际上得到了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'}
Run Code Online (Sandbox Code Playgroud)

本质上,当查看 $PYTHONBREAKPOINT 时,它的作用是:

from ipdb import set_trace  # function imported on the right-most `.`
set_trace()
Run Code Online (Sandbox Code Playgroud)

同样,比普通的旧 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
Run Code Online (Sandbox Code Playgroud)

附注

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