Il seguente è un frammento di codice Python usando l'AST e symtable pacchetti. Sto cercando di analizzare il codice e controllare i tipi. Ma io non capisco come attraversare oggetti per arrivare alla variabile reale fa riferimento.pitone pacchetto AST: attraversamento oggetto gerarchie
Il codice seguente implementa un NodeVisitor, e una funzione viene presentato al compilatore e analizzata dal compilatore e l'ast camminato. La funzione analizzata (eval_types) riceve un paio di oggetti.
Qui di seguito sono i pezzi di codice che compongono l'esempio. Ho aggiunto alcuni commenti per ogni blocco. Per eseguire il codice, i "blocchi" devono essere riassemblati.
Le importazioni e una funzione per annullare il rientro un blocco di codice per l'analisi.
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)
Quello che segue è il visitatore del nodo, ha le generici sovraccarichi visitatori non gestite e il nome.
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)))
seguito sono riportati alcuni semplici classi che saranno utilizzati nella funzione che verrà analizzato e analizzati con l'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()
Il seguente è la funzione di test, la funzione eval_types è la funzione che verrà analizzata con l'AST.
def testFunc(x,y,xo,z):
def eval_types():
z.val = x + y + xo.xi.x + xo.xf.x
return eval_types
Il codice per eseguire l'esempio, compilare la funzione e analizzare.
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)
Quanto segue è un esempio di output fino alla prima visita del nome.
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']
Creazione del visitatore nodo non sembra male, ma io non riesco a capire come attraversare una gerarchia di oggetti. Nel caso generale la variabile cui si accede potrebbe essere sepolto in un oggetto. Come arrivare alla variabile attuale a cui si accede dal visitatore ast? Vedo solo che un oggetto è al nodo non sono disponibili ulteriori informazioni qual è il risultato di accesso variabile.
non so seguire quello che vuoi. è che non riesci a trovare ".val"? hai provato a ricorrere sotto quel nodo? è passato molto tempo da quando l'ho usato, ma mi sembra di ricordare che nel tuo caso avresti bisogno di chiamare visit_children da visit_name. –
@andrewcooke Grazie per i commenti! Sì, desidero continuare l'analisi degli oggetti (z.val, xo.xi.x, xo.xf.x) e determinare ulteriori informazioni sulla variabile effettiva utilizzata nell'istruzione. Il caso semplice sarebbe, z = x + y + xo_xi_x + xo_xf_x, dove le variabili non sono incorporate (sepolte) negli oggetti e le proprietà/attributi/tipo della variabile potrebbero essere determinate nello snippet di codice sopra. Sperimenterò chiamando visit_children esplicitamente su questi tipi di nodi. Grazie ancora. –
Fare piccoli (lenti) progressi nello sviluppo di una comprensione del pacchetto AST. Per questo esempio, l'oggetto "attributi" percorrerà il ** visit_Attribute **. Ora ho semplicemente bisogno di determinare quando ** visit_Name ** ha un oggetto (ha figli?), Quindi termina in visit_Attribute e lavora all'indietro (esegui il backup dell'albero). –