Comment extraire les noms d'une fonction simple?
-
13-09-2020 - |
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 .
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").