我正在尝试从一些开源 python 项目中读取一些源代码,比如 ipython。我经常发现很难跟踪不同类中方法的执行流程,即使使用 eclipse 的调试工具并逐步执行代码。我不太清楚为什么代码会跳转到远相关类中的某些方法。
我知道它必须是继承层次结构,但我发现很难遵循。是否有任何工具可以帮助理解代码的执行方式?喜欢可视化不同方法的执行顺序?希望这不是一个完全幼稚的问题。
谢谢。
我正在尝试从一些开源 python 项目中读取一些源代码,比如 ipython。我经常发现很难跟踪不同类中方法的执行流程,即使使用 eclipse 的调试工具并逐步执行代码。我不太清楚为什么代码会跳转到远相关类中的某些方法。
我知道它必须是继承层次结构,但我发现很难遵循。是否有任何工具可以帮助理解代码的执行方式?喜欢可视化不同方法的执行顺序?希望这不是一个完全幼稚的问题。
谢谢。
跳转是由您的函数调用另一个函数引起的,该函数在 tern 调用另一个函数。
麻省理工学院网站有一个程序可以跟踪执行并以图片显示它们,您可能会发现它很有用:http: //people.csail.mit.edu/pgbovine/python/tutor.html#mode=edit
我和你在同一条船上。最后我创造了自己的东西。也就是说,您可以使用许多内置方法,但这需要一些努力。一种这样的方法是设置跟踪器——在代码执行时对代码进行某种分析器。
资源:
import sys, inspect
class Tracer(object):
def __init__(self):
self.tracing_packages = []
self.whitespace = ' '
self.indent_lvl = 0
def trace(self, frame, event, arg):
# Module info
mod = inspect.getmodule(frame)
if mod:
modpath = mod.__name__
else:
modpath = '<no module>'
# Just return if not interested in package
for to_trace in self.tracing_packages:
if not modpath.startswith(to_trace):
return self.trace
# Other info
fn_name = frame.f_code.co_name
src_lines = inspect.getsource(frame).split('\n')
src_line_start = src_lines[0]
src_line_end = src_lines[-1]
lineno = frame.f_lineno
ws = self.whitespace
# Printing
if event == 'call':
self.indent_lvl += 1
print('%scallin: %s %s %s' % (self.indent_lvl*ws, modpath, fn_name, str(arg)))
elif event == 'return':
if isinstance(arg, object):
ret = type(arg)
else:
ret = str(arg)
print('%sreturn: %s' % (self.indent_lvl*ws, ret))
self.indent_lvl -= 1
return self.trace
def watch_package(self, packname):
self.tracing_packages.append(packname)
用法
对于您的情况,您只需键入:
tracer = Tracer()
tracer.watch_package('IPython')
sys.settrace(tracer.trace)
然后,如果您尝试运行一个函数,您将打印整个调用链,包括被调用的同一包中的任何其他函数。
其他示例
当我想了解特定功能或整个包的流程时,我会使用它。如果您想要整个包的俯视图,您还可以使用 pylint 的pyreverse来创建 UML 图。
无论如何,这里是一个跟踪PyOCD包的示例:
>>> import sys, inspect, pyOCD
>>> tracer = Tracer()
>>> tracer.watch_package('pyOCD')
>>> sys.settrace(tracer.trace)
>>> pyOCD.board.MbedBoard.listConnectedBoards()
callin: pyOCD.board.mbed_board listConnectedBoards None
callin: pyOCD.board.mbed_board getAllConnectedBoards None
callin: pyOCD.interface.pyusb_backend getAllConnectedInterface
callin: pyOCD.interface.pyusb_backend __init__ None
callin: pyOCD.interface.interface __init__ None
return: <type 'NoneType'>
return: <type 'NoneType'>
callin: pyOCD.interface.pyusb_backend start_rx None
return: <type 'NoneType'>
return: <type 'list'>
...