【问题标题】:python3 bifurcated generatorpython3分叉生成器
【发布时间】:2018-11-17 16:23:58
【问题描述】:

我正在寻找一个代码来复制生成器,然后继续使用新的生成器。它就像发电机的分叉。

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

应用程序本身要复杂得多,这里只是一个代码示例。

Important(仅对我自己而言)是一个语义优美的解决方案,第三方可读性很好。效率并不那么重要

【问题讨论】:

标签: python python-3.x algorithm generator yield


【解决方案1】:

为什么不使用带有启动参数的生成器(当您使用它时使用停止参数)?

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

【讨论】:

  • 现在真的很漂亮。
  • 为什么不实际使用范围..?如果这是您的实际工作案例,那么使用生成器毫无意义。
  • @OlivierMelançon:你完全正确,我的问题的主要观点是不同的:这只是一个更复杂代码的简单示例,我现在正在编程。无论如何,感谢您的意见,它很有价值,让我走得更远。
【解决方案2】:

有些人会告诉你使用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() 更快。

【讨论】:

  • 与其依赖于完全没有记录的事实,即 tee 重用输入的底层 tee 结构,您可以使用几乎没有记录的事实,即 tee 可通过copy.copy 复制。
  • (Tee 可复制的唯一文档是 Python 2 文档中的 tee_lookahead 示例,位于 itertools recipes 的末尾。)
  • 我正在寻找一个漂亮的解决方案(效率不是那么重要)。所以我喜欢你的 itertools.tee 解决方案。您的行 lst = list(generator()) 不是必需的。
  • @user2357112 重点是,据记载 tee 不应在这里使用
  • @MarcelSonderegger 不,这里的重点是你不能使用 tee,它可能适得其反
猜你喜欢
  • 1970-01-01
  • 2021-11-12
  • 2017-04-06
  • 1970-01-01
  • 2018-01-19
  • 1970-01-01
  • 2015-03-04
  • 1970-01-01
  • 2021-12-04
相关资源
最近更新 更多