10

私はこのコードを持っています:

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)

関数'func'から抽出したい:

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

または次のようなもの:

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

編集

私がこれを行う必要があると思う理由を説明するためのいくつかの背景

簡単なPython関数のコードをスプレッドシートの数式に変換したいと思います。

だから私は変換する必要があります:

foo.bar - foo.baz

に:

=A1-B1

サンプルスプレッドシートhttp://img441.imageshack.us/img441/1451/84516405.png

**再編集*

私がこれまでに持っているもの。

以下のプログラムは以下を出力します。

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

コード:

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

ここでいくつかのリソースを見つけました:Python内部:Python ASTの操作ここで 、動作するcodegenモジュールを取得しました。

4

3 に答える 3

6
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

出力:

['foo.bar', 'foo.baz']
于 2010-07-11T09:47:23.630 に答える
1

名前を取得する必要がある理由がわかりません。すべての名前とドットを機能させるための非常に大雑把な方法は次のとおりです。

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

出力:

def func foo return foo . bar foo . baz

構文ツリーをよりエレガントに読むことで、それを改善できるかもしれません。私はpython 2.5を使用しているため、astモジュールの代わりにパーサーを使用しています。

于 2010-07-09T13:58:26.000 に答える
0

私はまだ新しいastモジュールを使用していませんが、古いcompiler.astを使用して同様のことを実現するコードを使用しています。

    def visitGetattr(self、node):
        full_name = [node.attrname]
        親=node.expr
        while isinstance(parent、compiler.ast.Getattr):
            full_name.append(parent.attrname)
            親=parent.expr
        isinstance(parent、compiler.ast.Name)の場合:
            full_name.append(parent.name)
            full_name = "。"。join(reversed(full_name))
            #full_nameで何かをする
        node.getChildNodes()のcの場合:
            self.visit(c)

コードを少し言い換えると、不注意なバグが発生した可能性があります。これで一般的な考え方が得られることを願っています。NameノードとGetattrノードの両方にアクセスして点線の名前を作成し、すべての中間値(たとえば、「foo」と「foo.bar」)も表示されるという事実にも対処する必要があります。 )。

于 2010-07-10T11:57:12.083 に答える