Python:如何创建递归生成器函数

8 投票
1 回答
7088 浏览
提问于 2025-04-17 07:50

我一直在研究一个生物问题,想要生成所有可能的子模型。我有一个可以正常工作的递归函数,它能生成我想要的所有子模型的大列表。不过,这些列表增长得非常快,变得难以管理(当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)

这个函数能给我提供我需要的子模型列表。

现在,我想用递归来得到同样的列表。起初,我天真地以为只要把result.append()换成yield,其他部分就能正常工作。所以我试了试这个:

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语句一次,然后就停止了,也就是说递归不再工作了。

有没有办法把我第一个笨重的列表生成函数变成一个简洁的生成器函数?我是不是漏掉了什么简单的东西?非常感谢任何帮助!

1 个回答

27

你应该把这个改成:

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)

撰写回答