Python 从文本块动态生成生成器函数

Python 从文本块动态生成生成器函数,python,generator,Python,Generator,(从我之前发布的一个过于冗长的问题简化而来!) 给定一个包含有效Python代码且包含“yield”语句的Python字符串,如何构造一个生成器来执行该字符串 例如,给定字符串: code_string = """for x in range(0, 10): yield x """ 我想构造一个生成器f,它执行代码\字符串,以便(在这个特定示例中): 请注意,代码字符串是任意的,因此此断言仅对上面的示例有效。code_字符串可以包含任何包含yield语句的有效python代码 谢谢 编

(从我之前发布的一个过于冗长的问题简化而来!)

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

例如,给定字符串:

code_string = """for x in range(0, 10):
    yield x
"""
我想构造一个生成器f,它执行代码\字符串,以便(在这个特定示例中):

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

谢谢

编辑:

我想到的第一个解决方案是在字符串中插入“def():”并以编程方式缩进每一行。但是,如果代码字符串使用不同的缩进,则该操作将失败。我希望有一些鲜为人知的functools功夫可以从一团文本构造函数

编辑2:

我还尝试在函数中使用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]
尝试:


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

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

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

相信我,这不是您想要解决的问题部分。:-)我感谢您的建议,但我喜欢解决问题。我删除了我的答案,因为我不知道如何让它工作(我认为exec()只在调用闭包生成的函数时被调用,而不是在调用生成函数时被调用)。我建议像伊格纳西奥建议的那样,寻找另一种方法来解决这个问题。我认为伊格纳西奥所说的是,你的问题不是你所想的。如果你能做到这一点,那么你将有复杂的意大利面代码,没有人会理解。几乎可以肯定有更好的办法,我理解。我不同意你的评估,我会有“没有人会理解的复杂的意大利面代码”。此解决方案取代了以前的即席DSL,后者发展成数百行pyparsing和正则表达式,是复杂的意大利面代码。我想我们都同意Python是一种非常清晰和简洁的语言,我认为它是DSL的理想选择。在我看来,使用“yield”关键字返回结果似乎相当优雅。干杯谢谢,如果传入的代码使用4个空格的缩进,就可以了。但是,有效的Python也可以使用两个空格的缩进。我正在寻找一个解决方案,可以处理任意值的代码字符串。我刚刚想到了这个。。。用正则表达式很容易检测缩进。max(min([indications]),4)将给出正确的值。事实就是这样!我(错误地)认为缩进必须在整个编译模块中保持一致。谢谢
exec( """def f():
        for x in range(0, 10):
               yield x
""" )


for x in f():
    print x
exec "def f():\n " + " \n".join(code_string.splitlines()) + "\n"