Python Debugger

pdb

The Python Debugger Pdb
可以直接在命令行中启动,调试程序
也可以写在代码中

命令行使用

可以直接在命令行指定要进行调试的程序

python -m pdb my_test.py

之后会显示当前代码执行的位置
通过输入命令进行操作

命令

<thead>
    <th>命令</th>
    <th>作用</th>
</thead>
<tbody>
    <tr>
        <td>h(elp)</td>
        <td>帮助</td>
    </tr>
    <tr>
        <td>w(here)</td>
        <td>打印当前堆栈</td>
    </tr>
    <tr>
        <td>d(own)[count]</td>
        <td>执行跳转到当前堆栈的深 [count] 层,默认为 1</td>
    </tr>
    <tr>
        <td>u(p)</td>
        <td>执行跳转到当前堆栈的上 [count] 层,默认为 1</td>
    </tr>
    <tr>
        <td>b(reak)[ ([filename:]lineno | function) [, condition] ]</td>
        <td>
            不加参数:列出所有断点;
            指定行号:(可以指定其他文件的一行) 在当前行添加断点;
            指定函数:在函数的第一个可执行语句添加断点;
            指定条件:当条件语句满足时断点生效
        </td>
    </tr>
    <tr>
        <td>tbreak[ ([filename:]lineno | function) [, condition] ]</td>
        <td>临时断点,生效一次后自动删除,使用方法同 b(reak)</td>
    </tr>
    <tr>
        <td>cl(ear)</td>
        <td>
            不加参数:清除所有断点;
            指定行号:(可以指定其他文件的一行) 清除当前行断点;
            指定断点号:清除此断点
        </td>
    </tr>
    <tr>
        <td>disable bpnumber [bpnumber ...]</td>
        <td>停用断点</td>
    </tr>
    <tr>
        <td>enable bpnumber [bpnumber ...]</td>
        <td>激活断点</td>
    </tr>
    <tr>
        <td>condition bpnumber [condition]</td>
        <td>为此断点设定条件</td>
    </tr>
    <tr>
        <td>s(tep)</td>
        <td>执行下一条命令,如果是函数调用,就执行到调用函数的第一句(会进入到调用的函数内部)</td>
    </tr>
    <tr>
        <td>n(ext)</td>
        <td>执行下一条语句,如果是函数调用,就执行函数,之后执行下一条语句(不会进入调用的函数内部)</td>
    </tr>
    <tr>
        <td>unt(il) [lineno]</td>
        <td>不带参数的情况下,继续执行,直到到达行号大于当前行的行号为止。使用[lineno],继续执行直到行号大于或等于[lineno]。</td>
    </tr>
    <tr>
        <td>r(eturn)</td>
        <td>继续执行,直至当前函数 return</td>
    </tr>
    <tr>
        <td>retval</td>
        <td>打印函数最后一次的返回值</td>
    </tr>
    <tr>
        <td>run [args...]</td>
        <td>重新启动程序,相当于restart</td>
    </tr>
    <tr>
        <td>c(ont(inue))</td>
        <td>继续执行,直至遇到断点</td>
    </tr>
    <tr>
        <td>l(ist)</td>
        <td>
            列出当前语句周围 11 行的源码。
            如果有一个参数,列出该行号周围 11 行的源码。
            如果有两个参数,列出区间内的源码。
            如果有两个参数,且后面的小,前面的参数为行号,后面参数为列出源码的行数。
        </td>
    </tr>
    <tr>
        <td>longlist | ll</td>
        <td>列出当前函数的全部源码</td>
    </tr>
    <tr>
        <td>a(rgs)</td>
        <td>列出当前函数的所有参数</td>
    </tr>
    <tr>
        <td>whatis arg</td>
        <td>打印参数类型</td>
    </tr>
    <tr>
        <td>p expression</td>
        <td>输出 expression 的值</td>
    </tr>
    <tr>
        <td>pp expression</td>
        <td>好看一点地输出 expression 的值</td>
    </tr>
    <tr>
        <td>q(uit) exit</td>
        <td>退出 debugger 停止执行语句</td>
    </tr>

set_trace

set_trace() 是最常用的断点方式,放置在代码中,程序会停在断点处,输入命令 c 继续运行

示例:

import pdb


def main(i):
    for i in range(i):
        pdb.set_trace()
        print(i)


if __name__ == '__main__':
    main(10)

输出:

> /dir/test.py(7)main()
-> print(i)
(Pdb) 

表示执行到 /dir/test.py 的第 7 行,main() 函数中,语句为 print(i)

breakpoint()

Python 3 中加入了内置函数 breakpoint() 可以直接调用 pdb,相当于 pdb.set_trace()

run & runeval

会在当前位置打断点,接下来会执行字符串类型的表达式

用法

run(cmd, globals=None, locals=None) 会对传入的参数执行 exec()
runeval(expr, globals=None, locals=None) 会对传入的参数执行 eval()

关于 exec()eval() <- 点击查看

如果不传入参数,则默认使用全局变量(__main__.dict)
如果要传入参数就要将全部参数以字典形式传入,使用没有传入的参数会报错

01-01 11:01