Отражение и модификация кода Python - PullRequest
3 голосов
/ 22 января 2011

Возможно, я не использую правильный термин, но я собираюсь взять блок кода Python (на Python), получить дерево токенов для кода, внести какие-то изменения и собрать его так, чтобыPython.

Например, рассмотрим этот блок кода:

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

Я хотел бы иметь возможность взять это и программно сделать это:

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

Iне могу представить, что нет библиотеки, которая делает что-то подобное.Заранее спасибо.

РЕДАКТИРОВАТЬ

Возможно, я не совсем понял.Я ищу инструмент для чтения и обработки произвольного кода, а не код, который я пишу.Я хотел бы иметь возможность изменять код на лету.Проект, над которым я работаю, представляет собой тестовое приложение: оно использует философию Netflix , чтобы попытаться произвольно нарушить функциональность приложения различными способами, каждый раз выполняя набор тестов.Когда тесты не проходят, есть признаки того, что в коде есть пробел и / или код мертв.

Ответы [ 4 ]

2 голосов
/ 22 января 2011

Мне было любопытно об этом, поэтому я посмотрел на ссылку, опубликованную Апалалой, вот что я придумал:

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 голос
/ 22 января 2011

В Python функции могут передаваться так же, как и любой другой объект, поэтому вы должны иметь возможность делать что-то вроде:

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

, а затем позвоните:

x(foo, y)

или

x(bar, y)

Вот урезанный, протестированный фрагмент (v 3.1), который демонстрирует концепцию без всякой бизлогии, только выполнение образца и произвольные числовые манипуляции:

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
0 голосов
/ 28 июля 2013

Вы можете изменить классы вашей программы, отражая, как это


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

0 голосов
/ 22 января 2011

Мне нужно угадать здесь случай использования, но я предполагаю, что в определенный момент времени вы хотите переключиться на одну функцию с другой. Это можно сделать относительно легко, используя словарь, заполненный функциями. Например:

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

...