代码之家  ›  专栏  ›  技术社区  ›  Joe

python递归生成器的范围

  •  2
  • Joe  · 技术社区  · 17 年前

    嘿,我正在开发一个递归生成器来创建数字的固定整数分区,我被范围问题搞糊涂了。

    代码与此代码段类似。

    def testGen(a,n):
        if n <= 1:
            print('yield', a)
            yield a
        else:
            for i in range(2):
                a[i] += n
                for j in testGen(a,n-i-1):
                    yield j
    

    我的困惑如下所示。

    >>> list(testGen([1,2],4))
    yield [10, 2]
    yield [10, 4]
    yield [10, 7]
    yield [12, 11]
    yield [12, 13]
    [[12, 13], [12, 13], [12, 13], [12, 13], [12, 13]]
    

    我只需使用数组的一个副本(例如传入)就可以得到正确的答案 a[:] 但是我仍然不理解上面的行为。 为什么打印语句和收益率值不同?

    4 回复  |  直到 17 年前
        1
  •  2
  •   John Fouhy    17 年前

    print语句在特定时间点显示列表。您的代码在运行列表时会对其进行更改,因此当您在末尾检查该列表时,就会看到它的值。

    您可以通过以下步骤观察到这一点:

    >>> g = testGen([1,2],4)
    >>> g.next()
    ('yield', [10, 2])   # note brackets in print statement because I'm on python 2.5
    [10, 2]
    >>> g.next()
    ('yield', [10, 4])
    [10, 4]
    >>> g.next()
    ('yield', [10, 7])
    [10, 7]
    >>> g.next()
    ('yield', [12, 11])
    [12, 11]
    >>> g.next()
    ('yield', [12, 13])
    [12, 13]
    
        2
  •  2
  •   Zach Snow    17 年前

    我猜你是在改变数组,所以当你打印它时,它有一个特定的值,下一次打印它时,它实际上已经更新了这个值,等等。最后,您有5个对同一数组的引用,所以当然您有5次相同的值。

        3
  •  2
  •   sykora    17 年前

    列表是可变的对象,如果传入一个列表,并且生成器在该列表上执行就地操作,那么最后对该列表的所有引用都将指向同一个列表。

        4
  •  0
  •   Unknown    17 年前

    print和yield语句是不同的,因为只有一个print语句,而有两个yield。试试这个:

    def testGen(a,n):
        if n <= 1:
            print('yield', a)
            yield a
        else:
            for i in range(2):
                a[i] += n
                for j in testGen(a,n-i-1):
                    print('yield', j)
                    yield j
    
    >>> list(testGen([1,2],4))
    ('yield', [10, 2])
    ('yield', [10, 2])
    ('yield', [10, 2])
    ('yield', [10, 2])
    ('yield', [10, 4])
    ('yield', [10, 4])
    ('yield', [10, 4])
    ('yield', [10, 4])
    ('yield', [10, 7])
    ('yield', [10, 7])
    ('yield', [10, 7])
    ('yield', [12, 11])
    ('yield', [12, 11])
    ('yield', [12, 11])
    ('yield', [12, 13])
    ('yield', [12, 13])
    ('yield', [12, 13])
    [[12, 13], [12, 13], [12, 13], [12, 13], [12, 13]]
    

    你会发现最后的收益率是你的答案,因为你一直在传递相同的列表,而不是复制。

    推荐文章