【问题标题】:Python nested generators not workingPython嵌套生成器不起作用
【发布时间】:2018-08-18 14:28:33
【问题描述】:

我正在练习生成器,我想知道为什么下面的代码不打印 16 对,而只打印 4 对。

def range_generator_function(my_range):
    for i in my_range:
        yield i

gen1=range_generator_function(range(1,5))
gen2=range_generator_function(range(1,5))

def pairs_generator_function(gen1,gen2):
    for it1 in gen1:
        for it2 in gen2:
            yield [it1,it2]

my_gen = pairs_generator_function(gen1,gen2)

for it in my_gen:
    print(it)

输出是

[1, 1]
[1, 2]
[1, 3]
[1, 4]

虽然我期望的输出是

[1, 1]
[1, 2]
[1, 3]
[1, 4]
[2, 1]
[2, 2]
[2, 3]
[2, 4]
[3, 1]
[3, 2]
[3, 3]
[3, 4]
[4, 1]
[4, 2]
[4, 3]
[4, 4]

【问题讨论】:

  • 生成器是单遍迭代器

标签: python generator


【解决方案1】:

您得到的输出是由于在第二次迭代中,生成器gen2 已耗尽。

您可以使用list 在循环之前存储其输出,也可以在每次迭代时使用itertools.tee 复制它。前者将无法处理无限生成器,但在实现后者之前,让我指出您实际上是在重新实现 itertools.product

from itertools import product

my_gen = product(gen1, gen2)

for it in my_gen:
    print(it)

【讨论】:

  • 这真的很有趣!
  • @Nisba 我不确定是否有人展示了解决您问题的代码,所以我将其添加到我的答案中。
【解决方案2】:

正如@wim 指出的那样,您的生成器在第一个迭代实例之后完全耗尽。但是,为了防止这种情况,在将gen1gen2 传递给pairs_generator_function 时将它们转换为列表。但是,您可以使用itertools.tee 存储原始生成器的两份副本:一份作为列表传递给函数,另一份供将来使用:

import itertools

def range_generator_function(my_range):
   for i in my_range:
     yield i

gen1=range_generator_function(range(1,5))
gen2=range_generator_function(range(1,5))

def pairs_generator_function(gen1,gen2):
  for it1 in gen1:
    for it2 in gen2:
        yield [it1,it2]

gen1, gen1_l = itertools.tee(gen1)
gen2, gen2_l = itertools.tee(gen2)
print(list(pairs_generator_function(list(gen1_l), list(gen2_l))))

输出:

[[1, 1], [1, 2], [1, 3], [1, 4], [2, 1], [2, 2], [2, 3], [2, 4], [3, 1], [3, 2], [3, 3], [3, 4], [4, 1], [4, 2], [4, 3], [4, 4]]

但是请注意,gen1 和 gen2` 仍然指向内存中的项目:

>>next(gen1)
1
>>next(gen2)
1

【讨论】:

    【解决方案3】:

    我修改了代码,所以我得到了想要的输出,现在生成器每次都在外循环内重新创建。

    def range_generator_function(my_range):
        for i in my_range:
            yield i
    
    def pairs_generator_function():
        gen1=range_generator_function(range(1,5))
        for it1 in gen1:
            gen2=range_generator_function(range(1,5))
            for it2 in gen2:
                yield [it1,it2]
    
    my_gen = pairs_generator_function()
    
    for it in my_gen:
        print(it)
    

    【讨论】:

      【解决方案4】:

      您在第一次通过内循环后耗尽了 gen2。该流中不再有任何内容,因此it1 的其他三个值没有可配对的内容。每次通过都需要重新启动gen2。考虑使用itertools.tee 克隆更多副本。

      【讨论】:

      • 我不认为这很复杂,但不得不通过 gen1 额外的时间是一个小小的遗憾。但是,它确实使解决方案处于封装状态。
      【解决方案5】:

      实际输出是正确的。您的 gen2 实例完全被第一个内部循环耗尽:

      def pairs_generator_function(gen1,gen2):
          for it1 in gen1:
              for it2 in gen2:  # <--- this consumes gen2
                  yield [it1,it2]
      

      在随后的迭代中,再次迭代 gen2 是空的。

      【讨论】:

      • 我怎样才能让它再次可用?
      • 你不能。生成器是一次性的。您必须在第一次迭代期间保存这些值,或者创建一个新的生成器。
      猜你喜欢
      • 2011-09-19
      • 2018-06-04
      • 2012-04-25
      • 2011-02-03
      • 1970-01-01
      • 2021-08-22
      • 2020-06-06
      • 2018-11-26
      • 2017-11-23
      相关资源
      最近更新 更多