从一团文本动态生成生成器函数

时间:2010-06-23 20:51:14

标签: python generator

(从我之前发布的过于冗长的问题中简化出来!)

如果Python字符串包含包含“yield”语句的有效Python代码,我该如何构造一个执行该字符串的生成器?

例如,给定字符串:

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

我想构造一个执行code_string的生成器f,以便(在这个特定的例子中):

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

请注意,code_string是 任意 ,因此此断言仅对上述示例有效。 code_string可以包含任何包含yield语句的有效python代码。

谢谢!

编辑:

我想到的第一个解决方案是将“def f():”放入字符串并以编程方式缩进每一行。但是,如果code_string使用不同的缩进,则会失败。我希望有一些鲜为人知的functools kung-fu可以用一团文字构建一个函数。

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 个答案:

答案 0 :(得分:2)

您关心在函数中使用缩进的内容是什么?缩进是相对的,不必一致。在前面添加“def f():\ n”,为你的函数中的每一行添加一个空格并执行它,你就完成了。这与你的答案一样有效:

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

(很抱歉听到您的pyparsing解决方案过于复杂。听起来您正在尝试重新创建一个完整的Python语法,只是为了向该语言添加一个或两个特性。在这种情况下,不是使用parseString解析整个事物,你可以添加一些专门的语法,为定义一个pyparsing表达式,编写一个从中创建Python代码的解析操作,并使用transformString搜索并用相应的Python行为替换特殊语法然后你可以执行或编译整个转换后的模块,只需要一点点的pyparsing。)

答案 1 :(得分:1)

尝试:

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


for x in f():
    print x