2012-02-24 1 views
11

을 계층 구조. 코드를 구문 분석하고 형식을 확인하려고합니다. 그러나 개체을 트래버스하는 방법을 이해하지 못하면 실제 변수 이 참조됩니다.파이썬 AST 패키지 : 오브젝트를 통과하는 것은 다음은 <em>AST</em> 및 <em>symtable</em> 패키지를 사용하여 파이썬 코드입니다

다음 코드는 NodeVisitor를 구현하며 함수는 컴파일러에 제공되고 컴파일러와 ast walked에 의해 구문 분석됩니다. 분석되는 함수 (eval_types)는 두 개의 객체로 전달됩니다.

다음은 예제를 구성하는 코드 청크입니다. 각 청크에 대해 몇 가지 설명을 추가했습니다. 코드를 실행하려면 "덩어리"를 다시 어셈블해야합니다.

구문 분석을 위해 코드 블록을 들여 쓰지 않는 가져 오기와 함수.

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 분석 될 기능에 사용되는 간단한 클래스이다.

class MyObj(object): 
    def __init__(self): 
     self.val = None 

class MyObjFloat(object): 
    def __init__(self): 
     self.x = 1. 

class MyObjInt(object): 
    def __init__(self): 
     self.x = 1 

class MyObjObj(object): 
    def __init__(self): 
     self.xi = MyObjInt() 
     self.xf = MyObjFloat() 

다음은 테스트 함수이며, 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이 발생하면 역순으로 처리하십시오.

관련 문제