Область применения рекурсивных генераторов Python - PullRequest
2 голосов
/ 12 мая 2009

Привет всем, я работал над рекурсивным генератором для создания фиксированных целочисленных разделов числа, и меня смутила проблема с областью видимости.

Код похож на этот фрагмент.

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 голосов
/ 12 мая 2009

Списки являются изменяемыми объектами, если вы передаете список, и генератор выполняет операции с этим списком на месте, то, наконец, все ссылки на список будут указывать на один и тот же список.

2 голосов
/ 12 мая 2009

Оператор печати отображает список в данный конкретный момент времени. Ваш код изменяет список по мере его запуска, поэтому к тому времени, когда вы просматриваете список в конце, вы видите его значение.

Вы можете наблюдать это, пройдя через:

>>> 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 голосов
/ 12 мая 2009

Я полагаю, что вы изменяете массив, поэтому, когда вы печатаете, он имеет определенное значение, затем при следующей печати он фактически обновит значение и так далее. В конце у вас есть 5 ссылок на один и тот же массив, поэтому, конечно, у вас есть одно и то же значение 5 раз.

0 голосов
/ 12 мая 2009

Операции print и yield различаются, потому что у вас есть только один оператор печати, а у вас 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):
                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]]

Вы увидите, что последними результатами являются ваши ответы, потому что вы обошли один и тот же список, а не сделали копию.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...