Python递归生成器的作用范围
大家好,我在做一个递归生成器,用来创建一个数字的固定整数分割时,遇到了一个作用域的问题,搞得我有点困惑。
我的代码大概是这样的。
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 个回答
2
我猜你的数组在被改变,所以第一次打印的时候它有一个特定的值,接下来再打印的时候这个值其实已经更新了,依此类推。最后,你有5个指向同一个数组的引用,所以当然会看到5次相同的值。
2
列表是可以改变的对象。如果你传入一个列表,并且生成器对这个列表进行了原地操作,那么最后所有指向这个列表的引用都会指向同一个列表。
2
打印语句会在特定的时刻显示列表的内容。你的代码在运行时会改变这个列表,所以当你最后查看这个列表时,你看到的是它那时的值。
你可以通过逐步执行代码来观察这一点:
>>> 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]