Question

J'ai ce morceau de code:

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 fonction 'Func' J'aimerais extraire:

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

ou quelque chose comme:

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

édité

Quelque fond pour expliquer pourquoi je pense avoir besoin de faire cela

Je veux convertir le code d'une fonction python triviale en formule de feuille de calcul.

Donc, j'ai besoin de convertir:

foo.bar - foo.baz

à:

=A1-B1

http://img441.imageshack.us/img441/1451/84516405 feuille de calcul de l'échantillon. png

** édité à nouveau *

Ce que j'ai jusqu'à présent.

Le programme ci-dessous Sorties:

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

Le code:

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

J'ai trouvé des ressources ici: Python Internals: Travailler avec Python Asts J'ai attrapé un module codegen travail .

Était-ce utile?

La solution

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

sortie:

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

Autres conseils

Je ne suis pas sûr de savoir pourquoi vous devez retirer des noms, une façon très brute d'obtenir tous les noms et les points de fonction sont

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

sortie:

def func foo return foo . bar foo . baz

Peut-être que vous pouvez améliorer cela en lisant la syntaxe de syntaxe plus élégamment, j'utilise un analyseur au lieu du module AST parce que je suis sur Python 2.5

Je n'ai pas encore utilisé le nouveau module AST, mais j'ai un code de travail qui utilise le plus ancien compiler.ast pour atteindre quelque chose de similaire:

    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)

Code légèrement paraphrasé, j'ai peut-être introduit des bugs par inadvertance.J'espère que cela vous donne l'idée générale: vous devez visiter les nœuds de nom et de getattr et de construire des noms en pointillé, et de faire face au fait que vous verrez également toutes les valeurs intermédiaires également (par exemple 'foo' et 'foo.bar' et "foo.bar").

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top