Область применения рекурсивных генераторов Python

StackOverflow https://stackoverflow.com/questions/850725

Вопрос

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

Код аналогичен этому фрагменту.

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]]

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top