2012-05-30 104 views
0

我正在嘗試從一些開源python項目(如ipython)讀取一些源代碼。我經常發現很難遵循不同類中方法的執行流程,甚至使用eclipse的調試工具並逐步執行代碼。我不太清楚爲什麼代碼跳轉到遠程相關類中的某些方法。如何在python中執行方法執行

我知道它必須是繼承層次結構,但我覺得很難遵循。有什麼工具可以幫助理解代碼的執行方式嗎?像可視化不同方法的執行順序一樣?希望這不是一個完全天真的問題。

謝謝。

+2

你見過或試過的任何代碼圖「分析」工具? – sarnold

+0

@sarnold剛剛嘗試了一個名爲pycallgraph的python模塊,它看起來很棒。 – qkhhly

回答

0

跳轉是由您的函數調用另一個函數引起的,它調用另一個函數。

0

我是在同一條船上,你。最後我創造了我自己的東西。也就是說,您可以使用許多內置方式,但需要付出一些努力。其中一種方法是設置一個示蹤器 - 執行代碼時的某種分析器。

來源:

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'> 

      ...