如何在惰性生成器链中跳过指定元素,仅对剩余元素应用后续生成器?
如何在惰性生成器链中跳过指定元素,仅对剩余元素应用后续生成器?
嘿,这个问题其实很好解决,核心就是把生成器的输出拆成两部分:要直接保留的前n个元素,和需要交给后续生成器处理的剩余元素。而且完全能保留生成器的惰性特性,不用一次性把所有元素加载到内存里。
先看针对你这个场景的具体实现,完全贴合你的需求:
def foo(): yield "pickles" yield from iter(range(4)) def bar(foo_numbers): yield from (5*num for num in foo_numbers) def create_foo_bar(): # 先拿到foo的生成器实例 foo_gen = foo() # 取出第一个元素直接返回(跳过处理的部分) first_item = next(foo_gen) yield first_item # 把剩下的所有元素传给bar处理,再返回结果 yield from bar(foo_gen) # 验证结果 foo_bar = list(create_foo_bar()) assert foo_bar == ['pickles', 0, 5, 10, 15]
这个逻辑特别直观:生成器是一次性迭代的,next(foo_gen)只会取出第一个元素"pickles",剩下的0、1、2、3还留在生成器实例里。把这个“剩了一半”的生成器传给bar后,bar的yield from会迭代剩余的所有元素,逐个乘5后输出,正好拼出你要的结果。
如果你以后需要跳过任意数量的元素(比如跳过n个,不是固定的1个),可以把这个逻辑封装成通用函数,复用性拉满:
def skip_n_then_apply(original_gen, skip_count, processor): # 先直接输出前skip_count个元素,不做任何处理 for _ in range(skip_count): try: yield next(original_gen) except StopIteration: # 如果生成器元素数量不够skip_count,直接终止避免报错 return # 把剩下的所有元素交给处理器函数处理后输出 yield from processor(original_gen) # 用通用函数实现你的需求 foo_bar = list(skip_n_then_apply(foo(), 1, bar)) assert foo_bar == ['pickles', 0, 5, 10, 15]
要是你习惯用标准库的工具,也可以用itertools.islice来实现类似效果,代码会更简洁一点:
import itertools def create_foo_bar(): foo_gen = foo() # 取前1个元素直接输出 yield from itertools.islice(foo_gen, 1) # 剩余元素交给bar处理 yield from bar(foo_gen)
本质上和手动用next的思路是一样的,都是拆分生成器的迭代流,把不需要处理的部分直接输出,需要处理的部分转交给后续生成器。
备注:内容来源于stack exchange,提问作者Him
相关产品推荐
相关产品推荐

