을 계층 구조. 코드를 구문 분석하고 형식을 확인하려고합니다. 그러나 개체을 트래버스하는 방법을 이해하지 못하면 실제 변수 이 참조됩니다.파이썬 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 방문자가 액세스하는 실제 변수를 얻는 방법은 무엇입니까? 오브젝트이 노드에 있지만 변수에 대한 액세스 결과가 무엇인지에 대한 추가 정보는 없습니다.
나는 당신이 원하는 것을 잘 모릅니다. ".val"을 찾을 수 없습니까? 그 노드 아래에서 재귀를 시도 했습니까? 나는 이것을 사용한 이후로 오랜 시간이 걸렸지 만, 귀하의 경우 visit_name에서 visit_children을 호출해야한다는 것을 기억하는 것 같습니다. –
@andrewcooke 의견 주셔서 감사합니다! 예, 객체 (z.val, xo.xi.x, xo.xf.x)를 계속 파싱하고 명세서에 사용 된 실제 변수에 대한 자세한 정보를 확인하고 싶습니다. 간단한 경우는 변수가 객체에 내장 (매입)되지 않고 변수의 속성/속성/유형이 위의 코드 스 니펫에서 결정될 수있는 z = x + y + xo_xi_x + xo_xf_x입니다. 이러한 유형의 노드에서 visit_children을 명시 적으로 호출하여 실험 해 보겠습니다. 다시 한번 감사드립니다. –
작은 (느린) 진행으로 AST 패키지에 대한 이해를 발전시킵니다. 이 예에서 객체 "속성"은 ** visit_Attribute ** 아래로 이동합니다. 이제 ** visit_Name **에 자식이있는 객체가 있는지 확인한 다음 visit_Attribute에서 끝내고 거꾸로 (트리를 백업) 작업 만하면됩니다. –