Python:如何编写递归生成器函数

7
我一直在生成一个生物问题的所有可能子模型。我已经有了一个工作递归函数,可以生成我想要的所有子模型的大列表。然而,这些列表很快变得难以管理(在下面的示例中N = 12刚好可行,但N> 12会使用过多的内存)。所以我想将其转换为使用yield的发生器函数,但是我卡住了。
我的递归函数如下:
def submodel_list(result, pat, current, maxn):
    ''' result is a list to append to
        pat is the current pattern (starts as empty list)
        current is the current number of the pattern
        maxn is the number of items in the pattern
    '''
    if pat:
        curmax = max(pat)
    else: 
        curmax = 0
    for i in range(current):
        if i-1 <= curmax:
            newpat = pat[:]
            newpat.append(i)
            if current == maxn:
                result.append(newpat)
            else:
                submodel_generator(result, newpat, current+1, maxn)

result = []
submodel_list(result, [], 1, 5)

这为我提供了符合我的目的的子模型列表。

现在,我想使用递归获取相同的列表。天真地,我认为我可以只用一个yield函数替换我的result.append(),其余部分就可以正常工作。因此,我尝试了以下内容:

def submodel_generator(pat, current, maxn):
    '''same as submodel_list but yields instead'''
    if pat:
        curmax = max(pat)
    else: 
        curmax = 0
    for i in range(current):
        print i, current, maxn
        if i-1 <= curmax:
            print curmax

            newpat = pat[:]
            newpat.append(i)
            if current == maxn:
                yield newpat
            else:
                submodel_generator(newpat, current+1, maxn)

b = submodel_generator([], 1, 5)
for model in b: print model

但现在我什么也得不到。通过(非常愚蠢的)挖掘,我发现该函数只有一次到达最终else语句,然后停止 - 即递归不再起作用。
是否有一种方法可以将我的第一个、笨拙的列表制作函数变成一个漂亮、整洁的生成器函数?我是否错过了什么傻乎乎的东西?非常感谢所有的帮助!

可能是重复的问题:Python:如何将递归算法用作生成器 - senderle
1
在Python 3.3中,您可以使用 yield from submodel_generator(...)。即将推出... - Dietrich Epp
@DietrichEpp,啊,那个被接受了吗?很酷。 - senderle
@senderle 我同意这与那篇帖子的性质非常相似,但不幸的是,我不擅长Python,无法理解那篇帖子为什么可以运作,因此我想发布我的类似示例,希望得到一些急需的帮助! - roblanf
1
yield from 的酷之处在于,与 for ... yield 不同的是,它可以正确处理生成器的 .send().throw() 方法。 - yak
@roblanf,我明白——这不是个人问题。我只是凭直觉行事。如果没有人同意我的看法,关闭投票将会消失。 - senderle
1个回答

26

你需要改为:

submodel_generator(newpat, current+1, maxn)

到这样:

for b in submodel_generator(newpat, current+1, maxn):
    yield b
这将递归地从连续调用函数中产生值。

[更新]: 请注意,从Python 3.3开始,您可以使用新的yield from语法:

yield from submodel_generator(newpat, current+1, maxn)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接