zoukankan      html  css  js  c++  java
  • pytorch Debug —交互式调试工具Pdb (ipdb是增强版的pdb)-1-使用说明

    初学时大多使用print或log调试程序,这在小规模的程序下很方便

    但是更好的方法是一边运行一边检查里面的变量和方法

    1.Pdb

    Pdb是一个交互式的调试工具,集成于Python标准库中

    Pdb能让你根据需求跳转到任意的Python代码断点、查看任意变量、单步执行代码,甚至还能修改变量的值,而不必重启程序

    ⚠️pdb 调试有个明显的缺陷就是对于多线程,远程调试等支持得不够好,同时没有较为直观的界面显示,不太适合大型的 python 项目。

    而在较大的 python 项目中,这些调试需求比较常见,因此需要使用更为高级的调试工具,如PyCharm IDE。

    手册:https://docs.python.org/3.5/library/pdb.html#pdbcommand-where

    pdb的使用方式和ipdb是一样的

    2.ipdb

    ipdb是增强版的pdb,参考https://github.com/gotcha/ipdb

    1)安装:

    (deeplearning) userdeMacBook-Pro:dogcat-6 user$ pip install ipdb
    Requirement already satisfied: ipdb in /anaconda3/envs/deeplearning/lib/python3.6/site-packages (0.12)
    ...

    ipdb提供了调试模式下的代码自动补全,还具有更好的语法高亮和代码溯源,以及更好的内省功能。它与pdb接口完全兼容

    2)结合PyTorch和ipdb进行调试

    1》集成到源代码中

    要使用ipdb,只需要在想要进行调试的地方插入语句:

    import ipdb
    ipdb.set_trace() #相当于添加断点

    当代码运行到这里,就会自动进入交互式调试模式

    上面的方式虽然简单,但是存在着两个较为比较明显的问题:

    1. 插入的断点代码会污染原来的代码空间 
    2. 每次插入断点都需要修改源码
    try:
        import ipdb
    except:
        import pdb as ipdb
        
    def sum(x):
        r = 0
        for ii in x:
            r += ii
        return r
    
    def mul(x):
        r =1
        for ii in x:
            r *= ii
        return r
    
    ipdb.set_trace()
    x = [1,2,3,4,5]
    r = sum(x)
    r = mul(x)

    当程序运行到ipdb.set_trace()语句时,会自动进入debug模式,在该模式中,我们可使用调试命令,如next或缩写n实现单步执行;也可以查看Python变量,或是运行Python代码

    如果Python变量名和调试命令冲突,需在变量名前加!,这样ipdb会执行对应的Python命令,而不是调试命令

    下面举例说明ipdb的调试

    这里重点讲解ipdb的两大功能:

    • 查看:在函数调用堆栈中自由跳动,并查看函数的局部变量
    • 修改:修改程序中的变量,并能以此影响程序的运行结果

    将上面的命令生成ipdb_test.py文件,使用命令行进行调试

    (deeplearning) userdeMacBook-Pro:pytorch-learning user$ python ipdb_test.py
    > /Users/user/pytorch/jupyter/pytorch-learning/ipdb_test.py(19)<module>()
         18 ipdb.set_trace()
    ---> 19 x = [1,2,3,4,5]
         20 r = sum(x)

    --->光标所指处为运行到的代码

    下面进行说明调试时能够使用的命令:

    l 1,18 : list 1,18的缩写,查看第1行到18行的代码

    ipdb> l 1,18                                                                    
          1 try:
          2     import ipdb
          3 except:
          4     import pdb as ipdb
          5 
          6 def sum(x):
          7     r = 0
          8     for ii in x:
          9         r += ii
         10     return r
         11 
         12 def mul(x):
         13     r =1
         14     for ii in x:
         15         r *= ii
         16     return r
         17 
         18 ipdb.set_trace()

    n : next的缩写,执行下一步;如果当前语句有一个函数调用,用 n 是不会进入被调用的函数体中的

    ipdb> n                                                                         
    > /Users/user/pytorch/jupyter/pytorch-learning/ipdb_test.py(20)<module>()
         19 x = [1,2,3,4,5]
    ---> 20 r = sum(x)
         21 r = mul(x)

    s : step的缩写,进入函数sum内部

    ipdb> s                                                                         
    --Call--
    > /Users/user/pytorch/jupyter/pytorch-learning/ipdb_test.py(6)sum()
          5 
    ----> 6 def sum(x):
          7     r = 0

    再继续单步执行,再在函数中继续执行,耶可以不用输入n,直接回车则会使用上次的命令

    ipdb> n                                                                         
    > /Users/user/pytorch/jupyter/pytorch-learning/ipdb_test.py(7)sum()
          6 def sum(x):
    ----> 7     r = 0
          8     for ii in x:
    
    ipdb> n                                                                         
    > /Users/user/pytorch/jupyter/pytorch-learning/ipdb_test.py(8)sum()
          7     r = 0
    ----> 8     for ii in x:
          9         r += ii
    
    ipdb> n                                                                         
    > /Users/user/pytorch/jupyter/pytorch-learning/ipdb_test.py(9)sum()
          8     for ii in x:
    ----> 9         r += ii
         10     return r

    u : up的缩写,跳回上一层的调用

    ipdb> u                                                                         
    > /Users/user/pytorch/jupyter/pytorch-learning/ipdb_test.py(20)<module>()
         19 x = [1,2,3,4,5]
    ---> 20 r = sum(x)
         21 r = mul(x)

    d : down的缩写,跳回之前调用到的下一层的位置

    ipdb> d                                                                         
    > /Users/user/pytorch/jupyter/pytorch-learning/ipdb_test.py(9)sum()
          8     for ii in x:
    ----> 9         r += ii
         10     return r

    当查看变量的命令和调试命令起冲突时,在前面加一个!

    查看r变量,该变量名与调试命令r(eturn) 起冲突

    ipdb> !r                                                                        
    0

    return : 继续运行,直到函数返回,结束该sum()函数的运算

    ipdb> return                                                                    
    --Return--
    15
    > /Users/user/pytorch/jupyter/pytorch-learning/ipdb_test.py(10)sum()
          9         r += ii
    ---> 10     return r
         11 

    当命令和调试命令没有冲突的时候,可以直接运行,不用添加!

    这里查看变量x的值,并对变量值进行修改

    ipdb> n                                                                         
    > /Users/user/pytorch/jupyter/pytorch-learning/ipdb_test.py(21)<module>()
         19 x = [1,2,3,4,5]
         20 r = sum(x)
    ---> 21 r = mul(x)
    
    ipdb> x                                                                         
    [1, 2, 3, 4, 5]
    ipdb> x[0] = 10000 

    b 13 : break的缩写,在13行处添加一个断点,如果没有添加位置则输出所有的断点信息

    ipdb> b 13                                                                      
    Breakpoint 1 at /Users/user/pytorch/jupyter/pytorch-learning/ipdb_test.py:13

    c : continue的缩写,继续运行,直到遇到断点

    ipdb> c                                                                         
    > /Users/user/pytorch/jupyter/pytorch-learning/ipdb_test.py(13)mul()
         12 def mul(x):
    1--> 13     r =1
         14     for ii in x:
    
    ipdb> return                                                                    
    --Return--
    1200000
    > /Users/user/pytorch/jupyter/pytorch-learning/ipdb_test.py(16)mul()
         15         r *= ii
    ---> 16     return r
         17 

    return后得到的是修改后的x的乘积

    l(ist) 或 ll : ll 是查看整个源码文件,l 可指定需要查看的行数,默认是当前往后 11 行,也可指定具体的范围

    ipdb> list                                                                      
         11 
         12 def mul(x):
    1    13     r =1
         14     for ii in x:
         15         r *= ii
    ---> 16     return r
         17 
         18 ipdb.set_trace()
         19 x = [1,2,3,4,5]
         20 r = sum(x)
         21 r = mul(x)

    pp 或 p expression: 打印变量的值,两者的不同是p用的是print(),pp用的是pprint()

    ipdb> pp x                                                                      
    [10000, 2, 3, 4, 5]
    ipdb> x                                                                         
    [10000, 2, 3, 4, 5]

    exit 或 q(uit) : 中止并退出

    ipdb> q                                                                         
    Exiting Debugger.

    关于ipdb的使用还又一些技巧:

    • <tab>键能够自动补齐,补齐用法与IPython中的类似
    • 可以直接在ipdb中修改变量的值
    • h(elp)能够查看调试命令的用法,比如h h可以查看h(elp)命令的用法,h jump能够查看j(ump)命令的用法

    其他命令:

    run 或 restart [args ...]:两者就是别名的关系,重新运行该python调试项目,如果提供了参数,会使用shlex进行分离,并将结果作为新的sys.argv。历史记录、断点、行动和调试选项都会保留。

    run [args ...]:这里的参数会作为运行脚本的参数

    (deeplearning) userdeMBP:pytorch-learning user$ python -m ipdb ipdb_test.py 
    /anaconda3/envs/deeplearning/lib/python3.6/runpy.py:125: RuntimeWarning: 'ipdb.__main__' found in sys.modules after import of package 'ipdb', but prior to execution of 'ipdb.__main__'; this may result in unpredictable behaviour
      warn(RuntimeWarning(msg))
    > /Users/user/pytorch/jupyter/pytorch-learning/ipdb_test.py(1)<module>()
    ----> 1 def sum(x):
          2     r = 0
          3     for ii in x:
    
    ipdb> run --x [3,3,3,3]                                                         
    Restarting ipdb_test.py with arguments:
        --x [3,3,3,3]
    > /Users/user/pytorch/jupyter/pytorch-learning/ipdb_test.py(1)<module>()
    ----> 1 def sum(x):
          2     r = 0
          3     for ii in x:
    
    ipdb> import sys                                                                
    ipdb> sys.argv                                                                  
    ['ipdb_test.py', '--x', '[3,3,3,3]']

    看到上面的结果,等价于 python ipdb_test.py --x [3,3,3,3],这个参数会作为运行sum(x)的参数

    如果要得到的是全新的调试器,使用exit 或 q(uit)

    通过b设置的断点在重新运行 debug 程序 (命令  restart 或  run) 后会依然保留,如果要忽略这些断点,有两种做法:

    • cl(ear) :如果后面带有参数,就是清除指定的断点;如果不带参数就是清除所有的断点
    (deeplearning) userdeMacBook-Pro:pytorch-learning user$ python ipdb_test.py
    > /Users/user/pytorch/jupyter/pytorch-learning/ipdb_test.py(19)<module>()
         18 ipdb.set_trace()
    ---> 19 x = [1,2,3,4,5]
         20 r = sum(x)
    
    ipdb> b 8                                                                       
    Breakpoint 1 at /Users/user/pytorch/jupyter/pytorch-learning/ipdb_test.py:8
    ipdb> cl 1                                                                      
    Deleted breakpoint 1 at /Users/user/pytorch/jupyter/pytorch-learning/ipdb_test.py:8
    ipdb> c       
    (deeplearning) userdeMacBook-Pro:pytorch-learning user$ 

    因为设置的断点被清除了,所以运行c会直接结束

    • disable/enable :禁用/激活断点
    (deeplearning) userdeMacBook-Pro:pytorch-learning user$ python ipdb_test.py
    > /Users/user/pytorch/jupyter/pytorch-learning/ipdb_test.py(19)<module>()
         18 ipdb.set_trace()
    ---> 19 x = [1,2,3,4,5]
         20 r = sum(x)
    
    ipdb> b 8                                                                       
    Breakpoint 1 at /Users/user/pytorch/jupyter/pytorch-learning/ipdb_test.py:8
    ipdb> b 9                                                                       
    Breakpoint 2 at /Users/user/pytorch/jupyter/pytorch-learning/ipdb_test.py:9
    ipdb> disable 1                                                                 
    Disabled breakpoint 1 at /Users/user/pytorch/jupyter/pytorch-learning/ipdb_test.py:8
    ipdb> c                                                                         
    > /Users/user/pytorch/jupyter/pytorch-learning/ipdb_test.py(9)sum()
    1     8     for ii in x:
    2---> 9         r += ii
         10     return r
    
    ipdb>         

    因为禁用了8处的断点,所以运行c直接就到了9的断点处

    j(ump) :让程序跳转到指定的行数 ,能够跳过中间某些行代码的执行

    注意:但是必须跳转的地方在当前的代码块中

    ipdb> j 13                                                                      
    *** Jump failed: line 13 comes after the current code block
    ipdb> j 10                                                                      
    > /Users/user/pytorch/jupyter/pytorch-learning/ipdb_test.py(10)sum()
    2     9         r += ii
    ---> 10     return r
         11 
    
    ipdb>   

    w(here) : 显示最近的一些栈帧信息

    ipdb> w                                                                         
      /Users/user/pytorch/jupyter/pytorch-learning/ipdb_test.py(20)<module>()
         19 x = [1,2,3,4,5]
    ---> 20 r = sum(x)
         21 r = mul(x)
    
    > /Users/user/pytorch/jupyter/pytorch-learning/ipdb_test.py(10)sum()
    2     9         r += ii
    ---> 10     return r
         11 

    a(rgs) : 返回目前函数的参数列表

    ipdb> a                                                                         
    x = [1, 2, 3, 4, 5]

    这个sum()函数现在的参数就只有一个x

     

    2》通过命令行进行交互

    这种方法与上面方法不同在于不需要在代码中插入断点语句,而是在运行时添加-m参数运行,然后再进行调试

    生成ipdb_test_command.py:

    #import ipdb  
    def sum(x):
        r = 0
        for ii in x:
            r += ii
        return r
    
    def mul(x):
        r =1
        for ii in x:
            r *= ii
        return r
    
    #ipdb.set_trace()
    x = [1,2,3,4,5]
    r = sum(x)
    r = mul(x)

    运行:

    (deeplearning) userdeMacBook-Pro:pytorch-learning user$ python -m ipdb ipdb_test_command.py
    /anaconda3/envs/deeplearning/lib/python3.6/runpy.py:125: RuntimeWarning: 'ipdb.__main__' found in sys.modules after import of package 'ipdb', but prior to execution of 'ipdb.__main__'; this may result in unpredictable behaviour
      warn(RuntimeWarning(msg))
    > /Users/user/pytorch/jupyter/pytorch-learning/ipdb_test.py(2)<module>()
          1 #import ipdb
    ----> 2 def sum(x):
          3     r = 0
    
    ipdb> n                                                                         
    > /Users/user/pytorch/jupyter/pytorch-learning/ipdb_test.py(8)<module>()
          7 
    ----> 8 def mul(x):
          9     r =1
    
    ipdb> n                                                                         
    > /Users/user/pytorch/jupyter/pytorch-learning/ipdb_test.py(15)<module>()
         14 #ipdb.set_trace()
    ---> 15 x = [1,2,3,4,5]
         16 r = sum(x)
    
    ipdb> n                                                                         
    > /Users/user/pytorch/jupyter/pytorch-learning/ipdb_test.py(16)<module>()
         15 x = [1,2,3,4,5]
    ---> 16 r = sum(x)
         17 r = mul(x)
    
    ipdb> s                                                                         
    --Call--
    > /Users/user/pytorch/jupyter/pytorch-learning/ipdb_test.py(2)sum()
          1 #import ipdb
    ----> 2 def sum(x):
          3     r = 0
    
    ipdb>      

    -m参数,这样调用ipdb_test_command.py的话断点就是程序的执行第一行之前

    然后就可以和上面一样使用命令进行调试

    3.支持的函数

    参考https://docs.python.org/3.5/library/pdb.html#pdbcommand-where

    该模块定义了以下功能;每个进入调试器的方式略有不同:

    pdb.set_trace()

      从正在运行的程序中插入调试器的典型用法是插入

    import pdb; pdb.set_trace()

    在要进入调试器的位置插入上面的函数。然后,你可以按照此语句逐步执行代码,并使用continue命令在没有调试器的情况下继续运行。

    大多数情况都只使用set_trace()函数和上面命令进行配合调试,下面的函数使用得比较少,没能查找到过多下面函数使用的情况,如果有小伙伴有这方面的资料,希望可以告知,谢谢

    pdb.run(statement, globals=None, locals=None)

    在调试器控制下执行语句(以字符串或代码对象的形式给出)。调试器提示符出现在执行任何代码之前;您可以设置断点并键入continue来运行到断点,或者使用step或next逐步执行语句。可选的全局变量和局部变量指定执行代码的环境;默认情况下使用模块__main__的字典。(参见内置的exec()或eval()函数的说明。)

    pdb.runeval(expression, globals=None, locals=None)

    计算调试器控制器下的表达式(以字符串或代码对象的形式给出)。当runeval()返回时,它返回表达式的值。否则,这个函数类似于run()。

    pdb.runcall(function, *args, **kwds)

    使用给定的参数调用函数(函数或方法对象,而不是字符串)。当runcall()返回时,它返回函数调用返回的任何值。一旦输入函数,调试器提示符就会出现。

    pdb.set_trace()

    在调用堆栈帧中输入调试器。这对于在程序中在给定点硬编码断点非常有用,即使代码没有被调试(例如,当断言失败时)。

    pdb.post_mortem(traceback=None)

    输入给定traceback对象的事后调试。如果没有给出traceback,则使用当前正在处理的异常之一(如果要使用缺省值,则必须处理异常)。

    pdb.pm()

    输入在sys.last_traceback中找到的traceback的事后调试。

    run*函数和set_trace()是实例化Pdb类和调用同名方法的别名。如果你想获得更多的功能,你必须自己做:

    class pdb.Pdb(completekey='tab', stdin=None, stdout=None, skip=None, nosigint=False)

    Pdb是调试器类。

    completekey、stdin和stdout参数被传递给底层cmd.Cmd类;

    如果给定了skip参数,则它必须是可迭代的全局样式模块名称模式。调试器不会进入起源于与这些模式之一匹配的模块中的框架。

    默认情况下,当您发出continue命令时,Pdb为SIGINT信号设置一个处理程序(当用户在控制台上按Ctrl-C时发送该信号)。这允许您通过按Ctrl-C再次进入调试器。如果希望Pdb不接触SIGINT处理程序,请将nosigint设置为true。

    启用跟踪与skip的例子调用:

    import pdb; pdb.Pdb(skip=['django.*']).set_trace()
    新版本3.1:skip参数。

    新版本3.2:nosigint参数。以前,Pdb从未设置过SIGINT处理程序。
  • 相关阅读:
    [Linux起步]常用命令
    Eclipse被SD杂志评为最佳开源工具
    [一点一滴学英语]20050921
    [一点一滴学英语]20050920
    [一点一滴学英语]20050919
    Longhorn (Vista) 推迟发布的背后
    最快速度找到内存泄漏
    重载(overload)、覆盖(override)、隐藏(hide) 详解
    HTTP请求和响应格式
    Skia之四——SkGradientShader篇
  • 原文地址:https://www.cnblogs.com/wanghui-garcia/p/10644935.html
Copyright © 2011-2022 走看看