Pregunta

Tengo este pedazo de código:

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)

de la función 'FUNC' me gustaría extraer:

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

o algo así como:

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

editado

Algunos antecedentes para explicar por qué creo que necesito hacer esto

Quiero convertir el código de una función trivial de python a una fórmula de hoja de cálculo.

Así que necesito convertir:

foo.bar - foo.baz

a:

=A1-B1

hoja de cálculo de muestra http://img441.imageshack.us/img441/1451/84516405. PNG

** editado de nuevo *

Lo que tengo hasta ahora.

El programa a continuación. Salidas:

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

El código:

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

Encontré algunos recursos aquí: Python Internals: Trabajando con Python ASTS Agarré un módulo de codegen de trabajo aquí .

¿Fue útil?

Solución

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

Salida:

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

Otros consejos

No estoy seguro de por qué necesita retirar los nombres, una forma muy cruda de obtener todos los nombres y los puntos en función es

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))

Salida:

def func foo return foo . bar foo . baz

Puede ser que puede mejorar eso al leer el árbol de sintaxis más elegante, estoy usando analizador en lugar del módulo AST AST porque estoy en Python 2.5

Todavía no he usado el nuevo módulo AST, pero tengo un código de trabajo que utiliza el compilador anterior.ast para lograr algo similar:

    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)

Código ligeramente desfavorecido, es posible que haya introducido errores involuntarios.Espero que esto le dé la idea general: debe visitar los nodos de Nombre y Getattr y construir nombres de puntos, y también lidiar con el hecho de que también verá todos los valores intermedios (por ejemplo, 'FOO' y 'FOO.BAR').

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top