开发者

Python code reflection and modification

开发者 https://www.devze.com 2023-02-05 20:58 出处:网络
Perhaps I\'m not using the proper term, but I\'m looking to take a block of Python code (in Python), get the token tree for the code, make some kind of modification, and re-assemble it to Python.

Perhaps I'm not using the proper term, but I'm looking to take a block of Python code (in Python), get the token tree for the code, make some kind of modification, and re-assemble it to Python.

For instance, consider this bl开发者_如何学Cock of code:

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

I would like to be able to take this and programmatically do this:

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

I can't imagine that there's not a library that does something like this. Thanks in advance.

EDIT

Perhaps I wasn't entirely clear. I'm looking for a tool to read and manipulate arbitrary code, not code that I'm writing. I'd like to be able to modify code on-the-fly. The project I'm working on is a test app: it uses the Netflix philosophy to try to randomly break the functionality of an app in as many ways as it can, running the test suite each time. When the tests don't fail, there's an indication that there's either a gap in code coverage and/or the code is dead.


I was curious about this so I looked into the link Apalala posted, here is what I came up with:

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)

And the result is:

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

Yeah I know, the spacing is ugly. I could not figure out how to maintain the format from the original code, but as far as functionality goes, this does what you want.


In Python functions can be passed just like any other object so you should be able to do something like:

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

and then call:

x(foo, y)

or

x(bar, y)

Here's a stripped down, tested snippet (v 3.1) that demonstrates the concept w/o any bizlogic, just sample execution and arbitrary numeric manipulation:

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

output:

>>> 
1
2


You can change your program classes by reflection like this


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


I'm going to have to guess about the usecase here, but I'll assume that at a certain point in time you want to switch for 1 function to the other. Doing this can be done relatively easily be using a dictionary filled with functions. For example:

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)

This will let you choose which function you want based simply on the dictionary key. You can do so simply by changing the value of func (for example to 'bar').

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号