Область применения рекурсивных генераторов 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[:]
к рекурсивному вызову), но я до сих пор не понимаю вышеуказанного поведения.Почему операторы печати и значения доходности различаются?
Решение
Оператор печати отображает список на данный конкретный момент времени.Ваш код изменяет список по мере его запуска, поэтому к тому моменту, когда вы просматриваете список в конце, вы уже видите его значение.
Вы можете наблюдать это, выполнив следующие действия:
>>> 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]
Другие советы
Я предполагаю, что вы изменяете массив, поэтому, когда вы печатаете, он имеет определенное значение, а затем в следующий раз, когда вы печатаете, он фактически обновляет значение и так далее.В конце у вас есть 5 ссылок на один и тот же массив, поэтому, конечно, вы получаете одно и то же значение 5 раз.
Списки — это изменяемые объекты. Если вы передаете список, а генератор выполняет над ним операции на месте, то в конечном итоге все ссылки на список будут указывать на один и тот же список.
Операторы печати и доходности различаются, поскольку у вас есть только один оператор печати, а у вас есть два выхода.Попробуй это:
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]]
Вы увидите, что последние результаты — это ваши ответы, потому что вы передавали один и тот же список вместо того, чтобы делать копию.