2012-02-24 8 views
11

次はASTsymtable パッケージを使用してPythonのコードスニペットですが階層。コードを解析して型をチェックしようとしています。しかし、私は オブジェクトをトラバースする方法を理解していないので、実際の変数 が参照されています。PythonのASTパッケージ:横断オブジェクトは、

次のコードはNodeVisitorを実装しており、関数はコンパイラに提示され、コンパイラとastが歩いて解析します。解析される関数(eval_types)には、2つのオブジェクトが渡されます。

以下は、この例を構成するコードチャンクです。各チャンクに対していくつかのコメントを追加しました。コードを実行するには、 "チャンク"を再アセンブルする必要があります。

構文解析用のコードブロックのインデントを取り消すためのインポートと関数。

import inspect 
import ast 
import symtable 
from tokenize import generate_tokens, untokenize, INDENT 
from cStringIO import StringIO 

# _dedent borrowed from the myhdl package (www.myhdl.org) 
def _dedent(s): 
    """Dedent python code string.""" 

    result = [t[:2] for t in generate_tokens(StringIO(s).readline)] 
    # set initial indent to 0 if any 
    if result[0][0] == INDENT: 
     result[0] = (INDENT, '') 
    return untokenize(result) 

以下はノードの訪問者である、それは一般的な未処理と名前​​ビジターオーバーロードがあります。

class NodeVisitor(ast.NodeVisitor): 
    def __init__(self, SymbolTable): 
     self.symtable = SymbolTable 
     for child in SymbolTable.get_children(): 
      self.symtable = child 
      print(child.get_symbols()) 

    def _visit_children(self, node): 
     """Determine if the node has children and visit""" 
     for _, value in ast.iter_fields(node): 
      if isinstance(value, list): 
       for item in value: 
        if isinstance(item, ast.AST): 
         print(' visit item %s' % (type(item).__name__)) 
         self.visit(item) 

      elif isinstance(value, ast.AST): 
       print(' visit value %s' % (type(value).__name__)) 
       self.visit(value) 

    def generic_visit(self, node): 
     print(type(node).__name__) 
     self._visit_children(node) 

    def visit_Name(self, node): 
     print(' variable %s type %s' % (node.id, 
             self.symtable.lookup(node.id))) 
     print(dir(self.symtable.lookup(node.id))) 

以下は、ASTで解析および解析される関数で使用される単純なクラスの一部です。

以下はテスト関数であり、eval_types関数はASTで解析される関数です。

def testFunc(x,y,xo,z): 

    def eval_types(): 
     z.val = x + y + xo.xi.x + xo.xf.x 

    return eval_types 

コードを実行すると、関数をコンパイルして解析します。

if __name__ == '__main__': 
    z = MyObj() 
    print(z.val) 
    f = testFunc(1, 2, MyObjObj(), z) 
    f() 
    print(z.val) 
    s = inspect.getsource(f) 
    s = _dedent(s) 
    print(type(s)) 
    print(s) 

    SymbolTable = symtable.symtable(s,'string','exec') 
    tree = ast.parse(s) 
    v = NodeVisitor(SymbolTable) 
    v.visit(tree) 

以下は、最初の訪問までの出力例です。

Module 
    visit item FunctionDef 
FunctionDef 
    visit value arguments 
arguments 
    visit item Assign 
Assign 
    visit item Attribute 
Attribute 
    visit value Name 
    variable z type <symbol 'z'> 
['_Symbol__flags', '_Symbol__name', '_Symbol__namespaces', 
'_Symbol__scope', '__class__', '__delattr__', '__dict__', 
'__doc__', '__format__', '__getattribute__', '__hash__', 
'__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', 
'__repr__', '__setattr__', '__sizeof__', '__str__', 
'__subclasshook__', '__weakref__', 'get_name', 'get_namespace', 
'get_namespaces', 'is_assigned', 'is_declared_global', 
'is_free', 'is_global', 'is_imported', 'is_local', 
'is_namespace', 'is_parameter', 'is_referenced'] 

ノードビジターを作成することは悪いようには見えませんが、私は、オブジェクト階層をトラバースする方法 を把握することはできません。一般的なケースでは、アクセスされる変数 は、オブジェクトの深くに埋め込むことができます。どのようにastの訪問者からアクセスされている実際の変数に到達するには? オブジェクトがノードにありますが、結果の変数アクセスが何であるかについての追加情報はありません。

+1

私はあなたが欲しいものに従うかわからない。あなたは ".val"を見つけることができないのですか?あなたはそのノードの下で再帰を試みましたか?私はこれを使用して以来、長い時間ですが、あなたの場合は、visit_nameからvisit_childrenを呼び出す必要があることを覚えているようです。 –

+0

@andrewcookeコメントありがとう!はい、私はオブジェクト(z.val、xo.xi.x、xo.xf.x)の解析を継続し、ステートメントで使用されている実際の変数の詳細を判断したいと思います。単純なケースは、変数がオブジェクトに埋め込まれておらず、変数のプロパティ/属性/タイプが上記のコードスニペットで決定できるz = x + y + xo_xi_x + xo_xf_xです。これらのタイプのノードでvisit_childrenを明示的に呼び出すことを試します。再度、感謝します。 –

+0

ASTパッケージの理解を発展させる小さな(遅い)進歩を作ります。この例では、オブジェクト「属性」は** visit_Attribute **を移動します。ここで、** visit_Name **にオブジェクトがあるかどうかを判断する必要があります(子供がいますか?)。その後、visit_Attributeで終了し、後方に作業します(ツリーをバックアップします)。 –

答えて

2

あなたがまだこれを探しているかどうかわかりませんが、visit_Attributeを追加して後方に移動する必要があるようです。あなたはあなたの例にこれを追加した場合:

def visit_Attribute(self, node): 
    print(' attribute %s' % node.attr) 
    self._visit_children(node) 

その後xo.xf.xのための出力は、次のとおりです。あなたはこれで何をしたいかによって

Add 
    visit value Attribute 
    attribute x 
    visit value Attribute 
    attribute xf 
    visit value Name 
    variable xo type <symbol 'xo'> 
    visit value Load 

は、あなただけになるまで、リスト内の属性を格納する必要がありますNameが発生した場合は、それらを逆にします。