当递归函数也是生成器时实际发生了什么?

What actually happens when a recursive function is also a generator?

我正在编写一个函数,给定一个数组,returns 一个可能的排列列表。 我想出了以下方法并且效果很好:

def _permutate(elems):
    if len(elems) <= 1:
        yield elems
    else:
        for i in range(len(elems)):
            for perm in _permutate(elems[:i] + elems[i+1:]):
                yield [elems[i]] + perm

所以 运行 print(list(_permutate([2, 1, 3]))) 给我:[[2, 1, 3], [2, 3, 1], [1, 2, 3], [1, 3, 2], [3, 2, 1], [3, 1, 2]]

但我想知道后台实际发生了什么... 我知道一个递归函数会添加到堆栈中,直到它到达它的基本情况,然后在堆栈中向后工作以给你一个结果,然后一个生成器函数在它的第一个 yield 和 returns 你有一个生成器时暂停计算循环获取每个产量的结果,但我真的很困惑当你把两者放在一起时会发生什么。


用调试语句重写函数

def _permutate(elems):
    if len(elems) <= 1:
        print(elems) # NEW
        yield elems
    else:
        for i in range(len(elems)):
            for perm in _permutate(elems[:i] + elems[i+1:]):
                print("NEW", [elems[i]], perm)  # NEW
                yield [elems[i]] + perm

然后运行

gen = _permutate([1,2,3,4,5])
print('NEXT', next(gen))
print('NEXT', next(gen))    
print('NEXT', next(gen))
print('NEXT', next(gen))
print('NEXT', next(gen))
print('NEXT', next(gen))
print('NEXT', next(gen))

更清楚地显示发生了什么:

[5]
NEW [4] [5]
NEW [3] [4, 5]
NEW [2] [3, 4, 5]
NEW [1] [2, 3, 4, 5]
NEXT [1, 2, 3, 4, 5]
[4]
NEW [5] [4]
NEW [3] [5, 4]
NEW [2] [3, 5, 4]
NEW [1] [2, 3, 5, 4]
NEXT [1, 2, 3, 5, 4]
[5]
NEW [3] [5]
NEW [4] [3, 5]
NEW [2] [4, 3, 5]
NEW [1] [2, 4, 3, 5]
NEXT [1, 2, 4, 3, 5]
[3]
NEW [5] [3]
NEW [4] [5, 3]
NEW [2] [4, 5, 3]
NEW [1] [2, 4, 5, 3]
NEXT [1, 2, 4, 5, 3]
[4]
NEW [3] [4]
NEW [5] [3, 4]
NEW [2] [5, 3, 4]
NEW [1] [2, 5, 3, 4]
NEXT [1, 2, 5, 3, 4]
[3]
NEW [4] [3]
NEW [5] [4, 3]
NEW [2] [5, 4, 3]
NEW [1] [2, 5, 4, 3]
NEXT [1, 2, 5, 4, 3]
[5]
NEW [4] [5]
NEW [2] [4, 5]
NEW [3] [2, 4, 5]
NEW [1] [3, 2, 4, 5]
NEXT [1, 3, 2, 4, 5]

找到一篇文章 here,其中显示了 table 在递归生成器期间发生的事情。 我试过用数组 [1,2,3] 重新创建这个 table

我做了一个实验来说明生成器的流程是如何工作的:

def _permutate(elems):
    if len(elems) <= 1:
        print(elems) # NEW
        yield elems
    else:
        for i in range(len(elems)):
            for perm in _permutate(elems[:i] + elems[i+1:]):
                print([elems[i]] + perm)  # NEW
                yield [elems[i]] + perm

# NEW
gen = _permutate([1,2,3,4,5])
print('NEXT', next(gen))
print('NEXT', next(gen))
print('NEXT', next(gen))
print('NEXT', next(gen))
print('NEXT', next(gen))
print('NEXT', next(gen))
print('NEXT', next(gen))

输出:

[5]
[4, 5]
[3, 4, 5]
[2, 3, 4, 5]
[1, 2, 3, 4, 5]
NEXT [1, 2, 3, 4, 5]
[4]
[5, 4]
[3, 5, 4]
[2, 3, 5, 4]
[1, 2, 3, 5, 4]
NEXT [1, 2, 3, 5, 4]
[5]
[3, 5]
[4, 3, 5]
[2, 4, 3, 5]
[1, 2, 4, 3, 5]
NEXT [1, 2, 4, 3, 5]
[3]
[5, 3]
[4, 5, 3]
[2, 4, 5, 3]
[1, 2, 4, 5, 3]
NEXT [1, 2, 4, 5, 3]
[4]
[3, 4]
[5, 3, 4]
[2, 5, 3, 4]
[1, 2, 5, 3, 4]
NEXT [1, 2, 5, 3, 4]
[3]
[4, 3]
[5, 4, 3]
[2, 5, 4, 3]
[1, 2, 5, 4, 3]
NEXT [1, 2, 5, 4, 3]
[5]
[4, 5]
[2, 4, 5]
[3, 2, 4, 5]
[1, 3, 2, 4, 5]
NEXT [1, 3, 2, 4, 5]