Динамическая генерация функции генератора из текста - PullRequest
1 голос
/ 24 июня 2010

(упрощено из-за слишком многословного вопроса, который я написал ранее!)

Учитывая строку Python, содержащую действительный код Python, который содержит оператор yield, как я могу сгенерировать генератор, который исполняет эту строку?

Например, с учетом строки:

code_string = """for x in range(0, 10):
    yield x
"""

Я хочу создать генератор f, который выполняет code_string так, чтобы (в этом конкретном примере):

assert(list(f()) == [0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

Обратите внимание, что code_string произвольно , поэтому это утверждение действительно только для приведенного выше примера. code_string может содержать любой допустимый код Python, который содержит оператор yield.

Спасибо!

Edit:

Первым решением, о котором я подумал, было просто ввести "def f ():" в строку и сделать программный отступ каждой строке. Однако это не работает, если code_string использует разные отступы. Я надеялся, что есть несколько малоизвестных functools кунг-фу, которые могут создать функцию из большого количества текста.

Edit2:

Я также попытался выполнить exec внутри функции, например:

code = "for x in range(0, 10): yield x"
def f():
    exec code in globals(), locals()

Это приводит к "SyntaxError: 'yield' вне функции"

Решено: Я стою исправлено, отступ относительно, так что это работает:

code_string = """for x in range(0, 10):
    yield x
"""

exec "def f():\n" + [(" " + line) for line in code_string.split('\n')]) + "\n"
assert list(f()) == [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

Ответы [ 2 ]

2 голосов
/ 24 июня 2010

Какое тебе дело, какие отступы используются в функции? Отступы относительны и не должны быть последовательными. Нажмите «def f (): \ n» в начале, добавьте один пробел к каждой строке в вашей функции и выполните его, и все готово. Это работает так же, как ваш ответ:

exec "def f():\n " + " \n".join(code_string.splitlines()) + "\n" 

(Жаль слышать, что ваше решение для синтаксического анализа было слишком сложным. Похоже, вы пытались воссоздать полную грамматику Python просто для добавления одной или двух функций к языку. В этом случае вместо анализа всего этого с помощью parseString, Вы можете просто добавить некоторый специализированный синтаксис, определить выражение pyparsing для только для этого синтаксиса , написать действие синтаксического анализа, создающее из него код Python, и использовать transformString для поиска и замены специального синтаксиса соответствующим поведением Python. Затем вы можете выполнить или скомпилировать весь преобразованный модуль, просто выполнив несколько операций разбора.)

1 голос
/ 24 июня 2010

Попробуйте:

exec( """def f():
        for x in range(0, 10):
               yield x
""" )


for x in f():
    print x
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...