以下是使用AST和symtable 包一個Python代碼段。我試圖解析代碼並檢查類型。但我 不明白如何遍歷對象去到被引用的實際變量 。的Python AST包:遍歷對象層次
下面的代碼實現了一個NodeVisitor,並且一個函數被呈現給編譯器並由編譯器解析並且ast走了。被分析的函數(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。 – 2012-03-05 04:20:13
@andrewcooke感謝您的評論!是的,我想繼續解析對象(z.val,xo.xi.x,xo.xf.x)並確定有關語句中使用的實際變量的更多信息。簡單的情況是,z = x + y + xo_xi_x + xo_xf_x,其中的變量沒有嵌入(掩埋)在對象中,變量的屬性/屬性/類型可以在上面的代碼片段中確定。我將嘗試在這些類型的節點上顯式調用visit_children。再次感謝。 – 2012-03-05 11:39:29
製作小型(慢速)進度,發展對AST包裝的理解。對於這個例子,對象「屬性」將沿着** visit_Attribute **行進。現在我只需要確定** visit_Name **何時有一個對象(有孩子?),然後在visit_Attribute中完成並向後工作(備份樹)。 – 2012-03-07 12:05:48