2

大家好,我正在使用递归生成器来创建数字的固定整数分区,但我对范围问题感到困惑。

该代码类似于此代码段。

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

4 回答 4

2

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

于 2009-05-12T01:13:36.353 回答
2

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]
于 2009-05-12T01:17:26.113 回答
2

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

于 2009-05-12T01:20:26.110 回答
0

print 和 yield 语句是不同的,因为您只有一个 print 语句,而您有 2 个 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]]

您将看到最后的产量是您的答案,因为您一直在传递相同的列表而不是制作副本。

于 2009-05-12T01:19:19.480 回答