2011-12-01 5 views
7

私はPythonコードで生成されたASTを "fun and profit"のために分析しています。実際に生成されたASTを実際に見るには "ast.dump"よりもグラフィカルなものがあります。Python astからドットグラフ

理論的には既に木であるので、グラフを作成するのは難しいことではありませんが、私はそれをどうやってできるのか分かりません。

ast.walkは、それはそう

... BFS戦略を歩いているようだ、と私は本当に親を見ることができないか、私は、グラフを作成する方法を見つけるように見えることはありませんvisitX方法唯一の方法は私自身のDFSウォーク関数を書くことですが、意味がありますか?

答えて

6

ast.NodeVisitorを見ると、それはかなり簡単なクラスです。それをサブクラス化するか、必要なものにウォーキング戦略を再実装するだけです。例えば、ノードが訪問されたときに親への参照を保持することは、この方法を実装するのが非常に簡単です。visitメソッドを追加して、親を引数として受け入れ、それ自身をgeneric_visitから渡すだけです。

P.S.ちなみに、NodeVisitor.generic_visitはDFSを実装しているようですので、親ノードを追加するだけです。

+0

はい、非常に単純な実装ですが、私は最初にすべてのケースをチェックしなければならないと考えましたが、実際にリストであるかどうかを確認しています。たくさん –

6

ファンタスティック、それが動作し、それがだから、通常のNodeVisitorと同じだが、私は、私はそれぞれの息子のためにノードの種類を追加しdefaultdictを持って

class AstGraphGenerator(object): 

    def __init__(self): 
     self.graph = defaultdict(lambda: []) 

    def __str__(self): 
     return str(self.graph) 

    def visit(self, node): 
     """Visit a node.""" 
     method = 'visit_' + node.__class__.__name__ 
     visitor = getattr(self, method, self.generic_visit) 
     return visitor(node) 

    def generic_visit(self, node): 
     """Called if no explicit visitor function exists for a node.""" 
     for _, value in ast.iter_fields(node): 
      if isinstance(value, list): 
       for item in value: 
        if isinstance(item, ast.AST): 
         self.visit(item) 

      elif isinstance(value, ast.AST): 
       self.graph[type(node)].append(type(value)) 
       self.visit(value) 

本当に簡単です。 それから、この辞書をpygraphviz.AGraphに渡して、私は素晴らしい結果を得ました。

唯一の問題は(タイプはあまり言っていないということですが、一方でast.dumpを使用しては)あまりにも冗長です。

各ノードの実際のソースコードを取得するのがベストでしょうか?

EDIT:今、それははるかに良いですが、そうでない場合は、単にタイプをプリントアウトし、私もコンストラクタでソースコードを渡すと、私は可能な場合は、コードの行を取得しよう。

class AstGraphGenerator(object): 

    def __init__(self, source): 
     self.graph = defaultdict(lambda: []) 
     self.source = source # lines of the source code 

    def __str__(self): 
     return str(self.graph) 

    def _getid(self, node): 
     try: 
      lineno = node.lineno - 1 
      return "%s: %s" % (type(node), self.source[lineno].strip()) 

     except AttributeError: 
      return type(node) 

    def visit(self, node): 
     """Visit a node.""" 
     method = 'visit_' + node.__class__.__name__ 
     visitor = getattr(self, method, self.generic_visit) 
     return visitor(node) 

    def generic_visit(self, node): 
     """Called if no explicit visitor function exists for a node.""" 
     for _, value in ast.iter_fields(node): 
      if isinstance(value, list): 
       for item in value: 
        if isinstance(item, ast.AST): 
         self.visit(item) 

      elif isinstance(value, ast.AST): 
       node_source = self._getid(node) 
       value_source = self._getid(value) 
       self.graph[node_source].append(value_source) 
       # self.graph[type(node)].append(type(value)) 
       self.visit(value) 
関連する問題