2011-11-29 75 views
41

在调试Python脚本时,我非常想知道整个程序的整个调用堆栈。一个理想的情况是,如果有一个python的命令行标志会导致Python打印所有函数名称,因为它们被调用(我检查了man Python2.7,但没有发现这种类型的东西)。如何在打印函数时调用

由于此脚本中的函数数量多,如果可能,我宁愿不在每个函数和/或类的开头添加打印语句。

一个中间解决方案是使用PyDev的调试器,放置几个断点并检查调用堆栈中的给定点在我的程序中,所以我暂时将使用这种方法。

如果存在这样的方法,我仍然希望看到程序整个生命周期中调用的所有函数的完整列表。

+1

分析器告诉你,例如所谓的所有功能http://docs.python.org/library/profile.html但不完全是你所要求的 - 这足够吗? – Mark

回答

70

您可以使用跟踪功能做到这一点(道具Spacedman为改善这种原始版本追查收益,并使用一些不错的缩进):

def tracefunc(frame, event, arg, indent=[0]): 
     if event == "call": 
      indent[0] += 2 
      print "-" * indent[0] + "> call function", frame.f_code.co_name 
     elif event == "return": 
      print "<" + "-" * indent[0], "exit function", frame.f_code.co_name 
      indent[0] -= 2 
     return tracefunc 

import sys 
sys.settrace(tracefunc) 

main() # or whatever kicks off your script 

注意函数的代码对象通常具有相同名称作为关联函数,但并非总是如此,因为函数可以动态创建。不幸的是,Python不会跟踪堆栈上的函数对象(我有时幻想着为此提交一个补丁)。不过,在大多数情况下,这肯定是“足够好”的。

如果出现这个问题,可以从源代码中提取“真实”函数名称--Python确实跟踪文件名和行号 - 或者让垃圾收集器找出哪个函数对象引用了代码对象。可能有多个函数共享代码对象,但他们的任何名字都可能足够好。

反观四年后重温这一点,我理应提的是Python 2.6和更高版本,可以通过使用sys.setprofile()而不是sys.settrace()获得更好的性能。可以使用相同的跟踪功能;只是当函数被输入或退出时才调用配置文件函数,所以函数内部全速执行。

+0

+1代表实际代码。 –

+1

我已经调整过显示函数返回。希望没关系! – Spacedman

+0

当然,越多越好:-) – kindall

2
import traceback 
def foo(): 
    traceback.print_stack() 
def bar(): 
    foo() 
def car(): 
    bar(): 

car() 
File "<string>", line 1, in <module> 
File "C:\Python27\lib\idlelib\run.py", line 97, in main 
    ret = method(*args, **kwargs) 
File "C:\Python27\lib\idlelib\run.py", line 298, in runcode 
    exec code in self.locals 
File "<pyshell#494>", line 1, in <module> 
File "<pyshell#493>", line 2, in car 
File "<pyshell#490>", line 2, in bar 
File "<pyshell#486>", line 2, in foo 

traceback

+1

这只是一个不太方便和不太灵活的方法,它可以完成OP已经使用调试器和断点进行的操作。 –

7

有几个选项。如果调试器不够用,可以使用sys.settrace()设置一个跟踪功能。这个函数基本上会在每一行Python代码执行时调用,但很容易识别函数调用 - 请参阅链接的文档。

您可能也对trace模块感兴趣,但它并不完全符合您的要求。请务必查看--trackcalls选项。

+0

是的,'sys.settrace()',与@ kindall的建议跟踪功能一起工作就像一个魅力。 :)'trace'模块看起来也非常有用......我会在未来的调试项目中记住它。 – James

2

您可以使用settrace,如下所示:Tracing python code。使用靠近页面末尾的版本。我将该页面的代码粘贴到我的代码中,以准确查看代码运行时执行的行。您也可以过滤,以便只能看到所调用函数的名称。

5

另一种很好的工具,要注意的是trace模块:

$ cat foo.py 
def foo(): 
    bar() 

def bar(): 
    print "in bar!" 

foo() 

$ python -m trace --listfuncs foo.py 
in bar! 

functions called: 
filename: /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/trace.py, modulename: trace, funcname: _unsettrace 
filename: foo.py, modulename: foo, funcname: 
filename: foo.py, modulename: foo, funcname: bar 
filename: foo.py, modulename: foo, funcname: foo 

$python -m trace --trace foo.py 
--- modulename: foo, funcname: 
foo.py(1): def foo(): 
foo.py(4): def bar(): 
foo.py(7): foo() 
--- modulename: foo, funcname: foo 
foo.py(2): bar() 
--- modulename: foo, funcname: bar 
foo.py(5): print "in bar!" 
in bar! 
--- modulename: trace, funcname: _unsettrace 
trace.py(80):   sys.settrace(None) 

+1

'trace'很有用,但是我找不到如何产生OP所要求的输出: '-l'只显示每个函数一次,'-t'显示每行。 –

相关问题