Python函数可以使用生成器并将生成器返回到其生成的输出的子集吗?

mik*_*ike 5 python generator

假设我有一个像这样的生成器函数:

import random
def big_gen():
  i = 0
  group = 'a'
  while group != 'd':
    i += 1
    yield (group, i)
    if random.random() < 0.20:
      group = chr(ord(group) + 1)
Run Code Online (Sandbox Code Playgroud)

示例输出可能是:('a',1),('a',2),('a',3),('a',4),('a',5),('a', 6),('a',7),('a',8),('b',9),('c',10),('c',11),('c',12) ,('c',13)

我想把它分为三组:A组,B组和C组.我想为每个组生成一个发生器.然后我将生成器和组字母传递给子功能.子功能的一个例子:

def printer(group_letter, generator):
  print "These numbers are in group %s:" % group_letter
  for num in generator:
    print "\t%s" % num
Run Code Online (Sandbox Code Playgroud)

期望的输出是:

These numbers are in group a:
1
2
3
4
5
6
7
8
These numbers are in group b:
9
These numbers are in group c:
10
11
12
13
Run Code Online (Sandbox Code Playgroud)

如何在不更改big_gen()或printer()的情况下执行此操作,并避免一次将整个组存储在内存中?(在现实生活中,团体巨大)

Ale*_*lli 8

当然,这可以做你想要的:

import itertools
import operator

def main():
  for let, gen in itertools.groupby(big_gen(), key=operator.itemgetter(0)):
    secgen = itertools.imap(operator.itemgetter(1), gen)
    printer(let, secgen)
Run Code Online (Sandbox Code Playgroud)

groupby在这里完成大部分工作 - key=只是告诉它要分组的字段.

生成的生成器需要包装在一个imapjust中,因为你已经指定了你的printer签名来取一个迭代器而不是数字,而本质上,groupby它将迭代器返回到它作为输入的相同项目 - 这里,2项元组与一个信后跟一个数字 - 但这与你的问题的标题并没有太大关系.

这个标题的答案是,是的,Python函数可以很好地完成你想要的工作 - itertools.groupby实际上就是这样.我建议仔细研究itertools模块,它是一个非常有用的工具(并提供出色的性能).