Python代码反射和修改

时间:2011-01-21 22:27:30

标签: python reflection abstract-syntax-tree

也许我没有使用正确的术语,但我正在寻找一段Python代码(在Python中),获取代码的令牌树,进行某种修改,并将其重新组装到蟒。

例如,考虑一下这段代码:

def x(y):
    b = 2
    if y == b:
        foo(y)

我希望能够以编程方式执行此操作:

def x(y):
    b = 2
    if y == b:
        bar(y)

我无法想象没有一个库可以做到这样的事情。提前谢谢。

修改

也许我并不完全清楚。我正在寻找一种工具来读取和操作任意代码,而不是我正在编写的代码。我希望能够即时修改代码。我正在开发的项目是一个测试应用程序:它使用Netflix philosophy尝试以尽可能多的方式随机破坏应用程序的功能,每次都运行测试套件。当测试没有失败时,表明代码覆盖率存在差距和/或代码已经死亡。

4 个答案:

答案 0 :(得分:2)

我对此很好奇所以我查看了Apalala发布的链接,这是我想出的:

from token import NAME
from tokenize import generate_tokens, untokenize
from StringIO import StringIO

source = """def x(y):
    b = 2
    if y == b:
        foo(y)"""
result = []
tokens = generate_tokens(StringIO(source).readline)
for toknum, tokval, _, _, _ in tokens:
    if toknum == NAME and tokval == "foo":
        tokval = "bar"
    result.append((toknum, tokval))

print untokenize(result)

结果是:

def x (y ):
    b =2 
    if y ==b :
        bar (y )

是的,我知道,间距很难看。我无法弄清楚如何从原始代码维护格式,但就功能而言,这可以满足您的需求。

答案 1 :(得分:1)

在Python中,函数可以像任何其他对象一样传递,因此您应该能够执行以下操作:

def x(fx, y):
    b = 2
    if y == b:
        fx(y)

然后致电:

x(foo, y)

x(bar, y)

这是一个精简的测试片段(v 3.1),演示了没有任何bizlogic的概念,只是示例执行和任意数字操作:

def x(fx, y): return fx(y)
def foo(x): return x
def bar(x): return x+1

print(x(foo,1))
print(x(bar,1))

输出:

>>> 
1
2

答案 2 :(得分:0)

您可以通过这样的反射来更改您的程序类


    class A(object):
        def __init__(self, x):
            self.x = x
        def show(self):
            print self.x

    def chglobals():
        import newmod
        reload(newmod)
        o = newmod.A(0)
        globals()['A'] = o.__class__

    def main():
        a = A(10)
        a.show()

        #change and wirte new code
        src = inspect.getsource(a.__class__)
        src = src.replace("print self.x", 'print "foo" ')
        text_file = open("newmod.py", "w")
        text_file.write(src)
        text_file.close()
        chglobals()

        #new istances
        b = A(20)
        b.show()

        #convert old istances
        a.__class__ = b.__class__
        a.show()


    main()

答案 3 :(得分:-1)

我将不得不在这里猜测用例,但我会假设在某个时间点你想要将1个功能切换到另一个。使用填充函数的字典可以相对容易地完成此操作。例如:

def foo(x): return x
def bar(b): return x+1
fn = { 'foo': foo, 'bar': bar }

def x(y):
    b = 2
    func = 'foo'
    if y == b:
        fn[func](y)

这样您就可以根据字典键选择所需的功能。您只需更改func的值(例如更改为“bar”)即可。