раздвоенный генератор python3 - PullRequest
0 голосов
/ 07 июня 2018

Я ищу код для копирования генератора и продолжения работы с новым генератором.Это как раздвоение генератора.

def Generator():
    myNumbers=range(3)
    for i in myNumbers:
        yield i

for i in Generator():
    bifurcatedGenerator = Generator
    for j in bifurcatedGenerator():
        print (i, j)

этот код выдает в качестве вывода:

0 0
0 1
0 2
1 0
1 1
1 2 <- wrong
2 0
2 1 <- wrong
2 2 <- wrong

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

0 0
0 1
0 2
1 1
1 2
2 2

Само приложение намного сложнее, здесь приведен лишь пример кода.

Важно (только для меня) это семантически красивое решение, которое приятнодля чтения третьим лицам. Эффективность не так важна

Ответы [ 2 ]

0 голосов
/ 07 июня 2018

Почему бы не использовать генератор с параметром запуска (и параметром останова, пока вы находитесь у него)?

def Generator(start=0, stop=3):
    for i in range(start, stop):
        yield i

for i in Generator():
    for j in Generator(start=i):
        print (i, j)

Также выдает вывод:

0 0
0 1
0 2
1 1
1 2
2 2
0 голосов
/ 07 июня 2018

Некоторые люди скажут вам использовать itertools.tee.Не используйте itertools.tee.

Используйте list

Чтобы отслеживать предыдущие состояния вашего генератора, вам нужно сохранить ранее полученные значения в list.Это то, что делает функция itertools.tee при копировании генератора.

К сожалению, это устраняет все преимущества памяти при использовании генератора.Поэтому вам лучше использовать list.

def generator():
    yield from range(3)

lst = list(generator())

for i in range(len(lst)):
    for j in range(i, len(lst)):
        print(lst[i], lst[j])

Вывод:

0 0
0 1
0 2
1 1
1 2
2 2

Почему бы тогда не использовать itertools.tee?

Это все еще возможноиспользуйте itertools.tee, но не следует.

from itertools import tee

def generator():
    yield from range(3)

lst = list(generator())

main_gen, bif_gen = tee(generator())

for i in main_gen:
    for j in bif_gen:
        print(i, j)
    _, bif_gen = tee(main_gen) # Yes, you *must* use the second item here

Причина, по которой предыдущий код работает, неуловима и фактически связана с тем фактом, что itertools.tee возвращает тот же объект tee в качестве первого выходного значения, когдадали tee объект.Вот почему следует использовать второй генератор.

Это, в сочетании с тем фактом, что doc явно указывает, что list лучше в этой ситуации, демонстрирует, что первое решение должнобыть предпочтительным:

Этот itertool может потребовать значительного вспомогательного хранения (в зависимости от того, сколько временных данных необходимо сохранить).В общем, если один итератор использует большую часть или все данные до запуска другого итератора, быстрее использовать list() вместо tee().

...