Python调试器:交互式调用函数时如何进入该函数

62

Python很酷,但不幸的是,它的调试器不像perl -d那样好。

当我在尝试代码时,经常会在调试器中从函数中调用并进入该函数:

# NOTE THAT THIS PROGRAM EXITS IMMEDIATELY WITHOUT CALLING FOO()
~> cat -n /tmp/show_perl.pl
1  #!/usr/local/bin/perl
2
3  sub foo {
4      print "hi\n";
5      print "bye\n";
6  }
7
8  exit 0;

~> perl -d /tmp/show_perl.pl

Loading DB routines from perl5db.pl version 1.28
Editor support available.

Enter h or `h h' for help, or `man perldebug' for more help.

main::(/tmp/show_perl.pl:8):    exit 0;

# MAGIC HAPPENS HERE -- I AM STEPPING INTO A FUNCTION THAT I AM CALLING INTERACTIVELY
  DB<1> s foo() 
main::((eval 6)[/usr/local/lib/perl5/5.8.6/perl5db.pl:628]:3):
3:      foo();


  DB<<2>> s
main::foo(/tmp/show_perl.pl:4):     print "hi\n";


  DB<<2>> n
hi
main::foo(/tmp/show_perl.pl:5):     print "bye\n";


  DB<<2>> n
bye


  DB<2> n
Debugged program terminated.  Use q to quit or R to restart,
  use O inhibit_exit to avoid stopping after program termination,
  h q, h R or h O to get additional info.  

  DB<2> q

当尝试步进函数处理不同输入以找出失败原因时,这非常有用。然而,在pdb或pydb中似乎都不能正常工作(我可以展示一个与上文类似的Python示例,但它会导致大量异常堆栈转储)。

所以我的问题有两个:

  1. 我有遗漏吗?
  2. 是否有一种Python调试器确实可以让我这样做?

显然,我可以在代码中自己加入调用,但我喜欢交互式地工作,例如在尝试使用略微不同的参数集调用时不必从头开始。

5个回答

50

我已经回答了自己的问题!这是在pydb中使用的“debug”命令:

~> cat -n /tmp/test_python.py
     1  #!/usr/local/bin/python
     2
     3  def foo():
     4      print "hi"
     5      print "bye"
     6
     7  exit(0)
     8

~> pydb /tmp/test_python.py
(/tmp/test_python.py:7):  <module>
7 exit(0)


(Pydb) debug foo()
ENTERING RECURSIVE DEBUGGER
------------------------Call level 11
(/tmp/test_python.py:3):  foo
3 def foo():

((Pydb)) s
(/tmp/test_python.py:4):  foo
4     print "hi"

((Pydb)) s
hi
(/tmp/test_python.py:5):  foo
5     print "bye"


((Pydb)) s
bye
------------------------Return from level 11 (<type 'NoneType'>)
----------------------Return from level 10 (<type 'NoneType'>)
LEAVING RECURSIVE DEBUGGER
(/tmp/test_python.py:7):  <module>

27

你也可以使用pdb来交互式地调试一个函数,前提是你想要调试的脚本在结束时没有使用exit()函数:

$ cat test.py
#!/usr/bin/python

def foo(f, g):
        h = f+g
        print h
        return 2*f

要调试,请启动一个交互式Python会话并导入pdb:

$ python
Python 2.5.1 (r251:54869, Apr 18 2007, 22:08:04) 
[GCC 4.0.1 (Apple Computer, Inc. build 5367)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import pdb
>>> import test
>>> pdb.runcall(test.foo, 1, 2)
> /Users/simon/Desktop/test.py(4)foo()
-> h = f+g
(Pdb) n
> /Users/simon/Desktop/test.py(5)foo()
-> print h
(Pdb) 

pdb模块随Python一起提供,并在模块文档中记录在http://docs.python.org/modindex.html


pdb.run或pdb.runeval将停止在代码的第一行,而pdb.runcall则不会,在调试时可能只会返回错误,我们需要使用%debug来检查后期情况,而不是所需的步骤。 - Frank

4

Python有一个名为“pdb”的调试器,它是Python核心发行版的一部分。我很少使用它,但有时会觉得它很有用。

考虑以下程序:

def foo():
    a = 0
    print "hi"

    a += 1

    print "bye"

foo()

以下是一个会话调试:

$ python /usr/lib/python2.5/pdb.py /var/tmp/pdbtest.py         ~
> /var/tmp/pdbtest.py(2)<module>()
-> def foo():
(Pdb) s
> /var/tmp/pdbtest.py(10)<module>()
-> foo()
(Pdb) s
--Call--
> /var/tmp/pdbtest.py(2)foo()
-> def foo():
(Pdb) s
> /var/tmp/pdbtest.py(3)foo()
-> a = 0
(Pdb) s
> /var/tmp/pdbtest.py(4)foo()
-> print "hi"
(Pdb) print a
0
(Pdb) s
hi
> /var/tmp/pdbtest.py(6)foo()
-> a += 1
(Pdb) s
> /var/tmp/pdbtest.py(8)foo()
-> print "bye"
(Pdb) print a
1
(Pdb) s
bye
--Return--
> /var/tmp/pdbtest.py(8)foo()->None
-> print "bye"
(Pdb) s
--Return--
> /var/tmp/pdbtest.py(10)<module>()->None
-> foo()
(Pdb) s

2
如果您更熟悉图形用户界面调试器,可以使用winpdb(在这种情况下,“win”并不是指Windows)。我实际上在Linux上使用它。
在Debian/Ubuntu上:
sudo aptitude install winpdb

如果您想要在代码中插入断点,请使用以下代码:

import rpdb2; rpdb2.start_embedded_debugger_interactive_password()

然后启动winpdb并附加到您正在运行的脚本。

到目前为止,它仅适用于Python2.7。https://bugs.launchpad.net/ubuntu/+source/winpdb/+bug/1126411 - Adam Ryczkowski

2

对于我正在开发的代码的交互式工作,我通常发现在代码本身中设置程序化“断点”更有效率,使用 pdb.set_trace。这使得在循环深处中断程序状态更加容易:if <state>: pdb.set_trace()


请参阅 https://dev59.com/DnVC5IYBdhLWcg3w51lv。 - Daryl Spitzer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接