【发布时间】:2010-06-23 20:51:13
【问题描述】:
(根据我之前发布的一个过于冗长的问题进行了简化!)
给定一个包含有效 Python 代码且包含“yield”语句的 Python 字符串,我如何构造一个生成器来执行该字符串?
例如,给定字符串:
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 可以包含任何包含 yield 语句的有效 python 代码。
谢谢!
编辑:
我想到的第一个解决方案是将“def f():”插入字符串并以编程方式缩进每一行。但是,如果 code_string 使用不同的缩进,则会失败。我希望有一些鲜为人知的 functools kung-fu 可以从文本块中构造函数。
编辑2:
我还在这样的函数中尝试了 exec:
code = "for x in range(0, 10): yield x"
def f():
exec code in globals(), locals()
这会导致“SyntaxError: 'yield' outside function”
已解决:我的立场是正确的,缩进是相对的,所以这可行:
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]
【问题讨论】:
-
相信我,这不是您要解决的问题的一部分。
-
:-) 我很欣赏这些建议,但我喜欢解决问题。
-
我删除了我的答案,因为我不知道如何使它工作(我认为 exec() 仅在调用闭包生成的函数时才被调用,而不是在生成函数时调用被称为)。正如 Ignacio 所建议的,我建议寻找另一种方法来解决这个问题。
-
我认为伊格纳西奥所说的是你的问题不是你想的那样。如果你让它工作,那么你将拥有没有人能理解的复杂的意大利面条代码。几乎可以肯定有更好的方法。
-
我明白这一点。我不得不不同意您的评估,即我将拥有“没有人会理解的复杂意大利面条代码”。该解决方案取代了以前的 ad-hoc DSL,后者发展成数百行 pyparsing 和正则表达式以及 IS 复杂的意大利面条代码。我认为我们都同意 Python 是一种非常清晰和简洁的语言,我认为它在这种情况下作为 DSL 是理想的。使用“yield”关键字返回结果对我来说似乎很优雅。干杯!