【问题标题】:Dynamically generating a generator function from a blob of text从文本块动态生成生成器函数
【发布时间】: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”关键字返回结果对我来说似乎很优雅。干杯!

标签: python generator


【解决方案1】:

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

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

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

【讨论】:

  • 原来如此!我的(错误的)印象是缩进必须在整个编译模块中保持一致。谢谢。
【解决方案2】:

试试:

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


for x in f():
    print x

【讨论】:

  • 谢谢,如果传入的代码使用 4 空格缩进,那就可以了。但是,有效的 Python 也可以使用 2 空格缩进。我正在寻找一种适用于 code_string 任意值的解决方案。
  • 我只是想到了这个……用正则表达式检测缩进很容易。 max(min([indentations]), 4) 将给出正确的值。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-12-07
  • 2014-03-10
  • 2020-12-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-07-16
相关资源
最近更新 更多