理解python中的嵌套yield/return

use*_*ser 19 python yield nested generator

我在python中有一个函数,其输出是一个生成器:

def main_function(x):
    r = get_range()
    for i in range(r):
        yield x+i
Run Code Online (Sandbox Code Playgroud)

我想重构代码(我已经简化了用例,但实际的计算可能很复杂而且更长.请参阅下面的编辑).根据我的理解,这是我应该做的,以保持功能不变:

(a)与原始代码相同的界面

    def sub_function(x,r):
        for i in range(r):
            yield x+i    

    def main_function(x):
        r = get_range()
        return sub_function(x,r)
Run Code Online (Sandbox Code Playgroud)

与其他方法相比:

(b)这将返回发电机的发电机(这种方法有什么优点吗?)

    def sub_function(x,r):
        for i in range(r):
            yield x+i    

    def main_function(x):
        r = get_range()
        yield sub_function(x,r)
Run Code Online (Sandbox Code Playgroud)

(c)这会破坏发电机的目的(这是正确的吗?)

    def sub_function(x,r):
        return [x+i for i in range(r)]

    def main_function(x):
        r = get_range()
        for i in sub_function(x,r):
            yield(i)
Run Code Online (Sandbox Code Playgroud)

编辑:评论指出正确的答案是用例依赖.我想补充一点,我的用例是解析XML文件以提取字段并将其写入数据库.这部分委托给sub_function().我还问了这个问题,以便对重构代码的嵌套yield的使用有一个大致的了解.

Aar*_*lla 12

你是对的; 最初的例子和a)做同样的事情,因为它们都返回一个生成器.

b)是不同的:它返回一个生成单个元素(另一个生成器)的生成器.要使用它,您需要两个循环(一个在外部,一个在内部生成器上).

本身没有任何优势,但有时,构建嵌套生成器可能很有用.

c)可能会更糟,但我很确定它[x for x in y]实际上也是作为发电机实现的.所以它有点贵,但不是那么多.

  • 至少对于2.x:`[x for y in y]`创建一个列表.`(x表示y中的x)`创建一个生成器(并且也不会在`locals()`中使用clobber/create`x`). (5认同)
  • 我曾做过一次并比较`list((x代表x中的x))`与`[x代表x in l]`并发现在python 2中第一个(1.96毫秒)慢于第二个(1.44毫秒)(对于10000项的列表,使用`python -mtimeit"l = range(10000)""list((x代表x中的x))"`和`python -mtimeit"l = range(10000)""[x for x in l]"`)但是在python 3中,第二个应该等于第一个,因为它们删除了在python 2中使用列表推导并将第二个转换为第一个的作弊. (3认同)
  • 我知道这个答案已经超过11年了。但是,至少在今天的 Python 3 中,替代“a”不应该使用“yield from”而不是“return”来等效吗?(或者`for i in sub_function(x,r):yield i`。) (2认同)