• 使用pdb交互式调试程序


    使用pdb交互式调试程序

    1.概述

    在调试程序时候,我们使用print输出调试信息的频率很高,但是这个方式效率却不高,有些时候追查程序出错原因也不是很方便。
    这次我们要介绍python内置的交互式调试器,他可以检查程序状态,打印变量信息。

    2.pdb介绍

    在其他大部分语言中,如果要使用调试器,那么必须现在源文件中设置断点,让程序执行到这一行停下来然后调试程序。而python不用这样,他可以直接在假设有问题的代码位置上加一条指令到程序停下来,启动调试器。采用这种方法来调试程序与正常启动程序并没有什么区别。
    尤其适合在没有IDE编辑器时,通过python命令界面调试运行中的代码非常的方便。

    2.1.pdb基本操作

    pdb调试代码支持在python命令界面使用和在IDE编辑器界面使用,下面介绍下在IDE编辑器中使用pdb调试器。

    在pdb提示符操作界面,可以通过help查看所有操作命令。下面列出常用操作命令:

    • where简写w:输出当前代码运行的位置
    • up简写u:跳转到执行调用栈上一层,回到当前函数调用者位置方便查看调用者位置的变量信息。例如A调用B函数,在B函数中跳转到A的位置。
    • down简写d:跳转到执行调用栈下一层,例如A调用B函数,在A函数中跳转到B的位置。
    • step简写s:执行程序里面的下一行代码,如果下一行代码是个函数则会进入函数内部。
    • next简写n:执行程序里面的下一行代码,如果下一行代码是个函数则不会进入函数内部。
    • return简写r:让程序一直运行到当前函数的返回为止
    • continue简写c:让程序运行到下一个断点位置
    • quit简写q:退出调试界面
    • p 变量名称:输出变量值
    • 变量名称:可以直接输入变量名称,输出变量的值
    • locals():输出当前函数里面所有局部变量值

    下面通过一个例子演示下操作pdb命令调试程序。

    import math
    
    def compute_rmse(observed, ideal):
        total_err_2 = 0
        count = 0
        for got, wanted in zip(observed, ideal):
            err_2 = (got - wanted) ** 2
            # 设置断点
            breakpoint()  # Start the debugger here
            total_err_2 += err_2
            count += 1
    
        mean_err = total_err_2 / count
        rmse = math.sqrt(mean_err)
        return rmse
    
    result = compute_rmse(
        [1.8, 1.7, 3.2, 6],
        [2, 1.5, 3, 5])
    print(result)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    运行上面的代码,他会停在断点的位置,然后通过pdb命令调试程序。

    # 输出某个变量值
    (Pdb) p err_2
    0.03999999999999998
    (Pdb) err_2
    0.03999999999999998
    
    # 输出当前函数中所有变量值
    (Pdb) locals()
    {'observed': [1.8, 1.7, 3.2, 6], 'ideal': [2, 1.5, 3, 5], 'total_err_2': 0, 'count': 0, 'got': 1.8, 'wanted': 2, 'err_2': 0.03999999999999998}
    
    # 查看当前程序运行的位置
    (Pdb) w
     /Users/edy/Documents/pythonwork/pyproject/flask_restX/src/app/suggest90/no_80.py(15)compute_rmse()
    -> total_err_2 += err_2
    
    # 运行到下一行代码
    (Pdb) n
    > /Users/edy/Documents/pythonwork/pyproject/flask_restX/src/app/suggest90/no_80.py(16)compute_rmse()
    -> count += 1
    
    # 退出运行
    (Pdb) q
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    2.2.事后调试器

    pdb还支持一项有用的功能,叫做事后调试,我们发现程序抛出异常并崩溃后,想通过调试器看看它在抛出异常的那一刻,究竟发生了什么。
    有时候我们不确定在哪里调用breakpoint函数,在这种情况下,尤其需要这项功能。
    下面来看一个示例
    在这个代码中调用compute_rmse函数传入了一个7j参数,会抛出异常。

    
    import math
    
    def compute_rmse(observed, ideal):
        total_err_2 = 0
        count = 0
        for got, wanted in zip(observed, ideal):
            err_2 = (got - wanted) ** 2
            total_err_2 += err_2
            count += 1
    
        mean_err = total_err_2 / count
        rmse = math.sqrt(mean_err)
        return rmse
    
    result = compute_rmse(
        [1.8, 1.7, 3.2, 7j],  # Bad input
        [2, 1.5, 3, 5])
    print(result)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    运行上面代码,下面是异常信息

     python3 -m pdb -c continue no_80.py
    
    # m:调用pdb命令
    # c:continue命令会让pdb在启动被测程序之后进入到断点位置,或运行到出现异常为止。
    
    # 运行结果
    TypeError: must be real number, not complex
    Uncaught exception. Entering post mortem debugging
    Running 'cont' or 'step' will restart the program
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    还有另一种方式可以触发事后机制,在运行代码遇到未捕获的异常后,在代码中引入pdb模块并调用pm函数。

    # 输入python3切换到python命令界面
     localhost:python3
     #导入模块
     >>> import my_module
     # 运行代码模块中的compute_stddev函数,下面是异常信息
    >>> my_module.compute_stddev([5])
    Traceback (most recent call last):
      File "", line 1, in <module>
      File "/Users/edy/Documents/pythonwork/pyproject/flask_restX/src/app/suggest90/my_module.py", line 20, in compute_stddev
        variance = compute_variance(data)
      File "/Users/edy/Documents/pythonwork/pyproject/flask_restX/src/app/suggest90/my_module.py", line 16, in compute_variance
        variance = err_2_sum / (len(data) - 1)
    ZeroDivisionError: float division by zero
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    上面的代码抛出了异常,下面使用pdb

    # 上面代码运行出现了异常信息,下面使用pdb查看错误信息。
    >>> import pdb; pdb.pm()
    > /Users/edy/Documents/pythonwork/pyproject/flask_restX/src/app/suggest90/my_module.py(16)compute_variance()
    -> variance = err_2_sum / (len(data) - 1)
    
    # 上面报错是这行代码,variance = err_2_sum / (len(data) - 1),下面查看下变量值。
    (Pdb) err_2_sum
    0.0
    (Pdb) len(data)
    1
    (Pdb) 
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
  • 相关阅读:
    yolov5分割+检测c++ qt 中部署,以opencv方式(详细代码(全)+复制可用)
    ET框架6.0分析二、异步编程
    部署LVS-DR+Keepalived高可用群集构建
    [附源码]计算机毕业设计springboot病房管理系统
    盘点| 爆款小游戏的开发引擎
    Talk | ICCV‘23清华大学博士生诸子钰:3D-VisTA通用统一的3D视觉语言预训练模型
    linux内核驱动开发
    Window 10安装MySQL 5.7
    技术干货 | MindSpore AI科学计算系列(五):AI框架加速海洋数值模拟
    Linux—文件编程
  • 原文地址:https://blog.csdn.net/m0_38039437/article/details/128120236