Domanda

Ho questo pezzo di codice:

import inspect
import ast

def func(foo):
    return foo.bar - foo.baz

s = inspect.getsource(func)
xx = ast.parse(s)

class VisitCalls(ast.NodeVisitor):
    def visit_Name(self, what):
        if what.id == 'foo':
            print ast.dump(what.ctx)

VisitCalls().visit(xx)
.

Dalla funzione 'func' mi piacerebbe estrarre:

['foo.bar', 'foo.baz']
.

o qualcosa del genere come:

(('foo', 'bar'), ('foo', 'baz))
.

modificato

alcuni sfondo per spiegare perché penso di dover fare questo

Voglio convertire il codice di una funzione di pitone banale in una formula del foglio di calcolo.

Quindi ho bisogno di convertire:

foo.bar - foo.baz
.

A:

=A1-B1
.

Esempio di calcolo http://img441.imageshack.us/img441/1451/84516405. PNG

** Modificato di nuovo *

Cosa ho finora.

Il programma qui sotto le uscite:

('A1', 5)
('B1', 3)
('C1', '= A1 - B1')
.

Il codice:

import ast, inspect
import codegen # by Armin Ronacher
from collections import OrderedDict

class SpreadSheetFormulaTransformer(ast.NodeTransformer):
    def __init__(self, sym):
        self.sym = sym
    def visit_Attribute(self, node):
        name = self.sym[id(eval(codegen.to_source(node)))]
        return ast.Name(id=name, ctx=ast.Load())

def create(**kwargs):
    class Foo(object): pass
    x = Foo()
    x.__dict__.update(kwargs)
    return x

def register(x,y):
    cell[y] = x
    sym[id(x)] = y

def func(foo):
    return foo.bar - foo.baz

foo = create(bar=5, baz=3)
cell = OrderedDict()
sym = {}

register(foo.bar, 'A1')
register(foo.baz, 'B1')

source = inspect.getsource(func)
tree = ast.parse(source)
guts = tree.body[0].body[0].value
SpreadSheetFormulaTransformer(sym).visit(guts)

code = '= ' + codegen.to_source(guts)
cell['C1'] = code

for x in cell.iteritems():
    print x
.

Ho trovato alcune risorse qui: Python Internals: Lavorare con Python ASTS Ho afferrato un modulo di codegen funzionante qui .

È stato utile?

Soluzione

import ast, inspect
import codegen # by Armin Ronacher

def func(foo):
    return foo.bar - foo.baz

names = []

class CollectAttributes(ast.NodeVisitor):
    def visit_Attribute(self, node):
        names.append(codegen.to_source(node))

source = inspect.getsource(func)

tree = ast.parse(source)
guts = tree.body[0].body[0].value
CollectAttributes().visit(guts)
print names
.

Uscita:

['foo.bar', 'foo.baz']
.

Altri suggerimenti

Non sono sicuro del motivo per cui hai bisogno di retirere i nomi, un modo molto grezzo per ottenere tutti i nomi e i punti in funzione è

import inspect
import parser
import symbol
import token
import pprint

def func(foo):
    return foo.bar - foo.baz

s = inspect.getsource(func)
st = parser.suite(s)

def search(st):
    if not isinstance(st, list):
        return
    if st[0] in [token.NAME, token.DOT]:
        print st[1],
    else:
        for s in st[1:]:
            search(s)

search(parser.ast2list(st))
.

Uscita:

def func foo return foo . bar foo . baz
.

Potrebbe essere possibile migliorare su quello leggendo l'albero della sintassi più elegantemente, sto usando il parser invece del modulo AST perché sono su Python 2.5

Non ho ancora usato il nuovo modulo AST, ma ho il codice di lavoro che usa il vecchio compilatore .Ast per ottenere qualcosa di simile:

    def visitGetattr(self, node):
        full_name = [node.attrname]
        parent = node.expr
        while isinstance(parent, compiler.ast.Getattr):
            full_name.append(parent.attrname)
            parent = parent.expr
        if isinstance(parent, compiler.ast.Name):
            full_name.append(parent.name)
            full_name = ".".join(reversed(full_name))
            # do something with full_name
        for c in node.getChildNodes():
            self.visit(c)
.

Codice leggermente parafrasato, potrei aver introdotto bug involontario.Spero che questo ti dà l'idea generale: devi visitare sia il nome che i nodi Getattr e costruisci i nomi punteggiati e affrontare anche il fatto che vedrai anche tutti i valori intermedi (ad es. "FOO" e "FOO.BAR").

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top