-1

我正在尝试编写一段代码,它将给我一个数字的分区。到目前为止,我想出了这个(在谷歌上找到)。

def gen(n):
           # tuple version
           if n == 0:
               yield ()
               return

           for p in gen(n-1):
               yield (1, ) + p
               if p and (len(p)<2 or p[1] > p[0]):
                   yield (p[0] + 1, ) + p[1:]

print(list(gen(5)))

如果有人能帮助我理解这个递归函数是如何工作的,我将不胜感激。请帮助。谢谢。

4

2 回答 2

3

为了理解发生了什么,它有助于打印生成器的输出,以获得几个顺序增加的值n

>>> for i in range(5):
        print(list(gen(i)))

[()]
[(1,)]
[(1, 1), (2,)]
[(1, 1, 1), (1, 2), (3,)]
[(1, 1, 1, 1), (1, 1, 2), (2, 2), (1, 3), (4,)]

每个序列的计算都基于它之前的序列。这是它如何工作的逐行解释:

if n == 0:
    yield ()
    return

生成器的前几行用于基本情况,其中n0。该return语句在产生一个空元组后使其退出,而不是继续执行其余代码。

for p in gen(n-1):

这是函数的递归步骤。由于gen是一个生成器,它是通过循环完成的,因此其余代码将重复运行,并p从递归结果中获取不同的值。

    yield (1, ) + p

这是一条重要的线。这样做是从生成器中产生一个新的元组,该元组通过将 a 连接1到 value 的前面而形成p。如果p是空元组,这将是一个 1 元组。如果p已经有一些值,则元组将变得更长。

    if p and (len(p)<2 or p[1] > p[0]):

这是一个复杂的条件。第二次检查,len(p)<2真的可以写len(p)==1,因为p and开头的部分已经排除了p为空。

p为了通过,可以有两种值。要么p只有一个值,要么有更多的值,并且它的第一个值小于它的第二个值。所以(3,)会过去,也会过去,(1,2)(1,1,1)不会。

        yield (p[0] + 1, ) + p[1:]

这是另一个元组连接。它将第一个值增加p一个,然后将其与其余部分连接起来p(使用切片)。So (3,)will become (4,)(切片为空), (1,2)become(2,2)等。

所以,现在让我们来看看我们上面看到的结果。

[()]

等于 0 时,基本情况被击中,你会得到n一个空元组。

[(1,)]

等于 1 时,n循环运行一次,并连接(1,)到空元组,产生 1-tuple (1,)。条件的第一部分if没有通过,因为p它是空的。

[(1,1), (2,)]

n等于 2,循环仍然只运行一次。首先,它(1,1)通过(1,)与自身连接得到 get (1,1)。但是这一次,该if块运行,因为p只有一个值。所以它也产生了(p[0]+1,) + p[1:]。其中的切片部分是空元组,但第一部分是(2,).

[(1,1,1), (1,2), (3,)]

现在终于循环运行不止一次了!虽然第一次,它将另一个连接(1,)到前面(1,1),并且由于if不满足语句的条件,这就是它所做的一切。然而,在第二次通过时,它会产生两个值,一次连接(1,)(2,)然后递增(2,)(3,).

[(1, 1, 1, 1), (1, 1, 2), (2, 2), (1, 3), (4,)]

这个我会留给你,让你走过。与上述情况一样,p它将采用上一级调用 ( (1,1,1), (1,2), (3,)) 中的每个值,并且对于每个值,它将产生一个或两个新结果。

于 2013-02-21T23:32:34.650 回答
0

yield把你的函数变成一个生成器。阅读此答案以获得很好的解释。

基本上,不是一次创建结果列表然后返回它:

def f():
    output = []

    for i in range(10):
        output.append(i + 3)

    return output

您可以创建一个生成器,yield仅当您请求一个项目时:

def f():
    for i in range(10):
        yield i + 3

也可以制作无限生成器:

def f():
    a = 0
    b = 1

    while True:
        yield b

        a, b = b, a + b

迭代f()只会不断吐出斐波那契数列的术语。

于 2013-02-21T20:52:21.570 回答