【发布时间】:2010-10-03 12:28:43
【问题描述】:
我有许多 Python 生成器,我想将它们组合成一个新的生成器。我可以通过使用一堆yield 语句的手写生成器轻松做到这一点。
另一方面,itertools 模块是为这样的事情而设计的,在我看来,创建我需要的生成器的 Python 方法似乎是将 itertools 模块的各种迭代器插入在一起。
然而,在手头的问题中,它很快变得相当复杂(生成器需要保持一种状态 --- 例如,是否正在处理第一个或后面的项目 ---,第 i 个输出进一步取决于第 i 个输入项的 on 条件和各种输入列表在加入到生成的列表之前必须进行不同的处理。
由于可以解决我的问题的标准迭代器的组成——由于编写源代码的一维性质——几乎难以理解,我想知道使用标准 itertools 生成器是否有任何优势与手写的生成器功能(在基本和更高级的情况下)。实际上,我认为在 90% 的情况下,手写版本更容易阅读 —— 可能是因为与链式迭代器的函数式风格相比,它们更具命令性。
编辑
为了说明我的问题,这里有一个(玩具)示例:让a 和b 成为两个长度相同的迭代(输入数据)。 a 的项目由整数组成,b 的项目本身是可迭代的,其各个项目是字符串。输出应对应于以下生成器函数的输出:
from itertools import *
def generator(a, b):
first = True
for i, s in izip(a, b):
if first:
yield "First line"
first = False
else:
yield "Some later line"
if i == 0:
yield "The parameter vanishes."
else:
yield "The parameter is:"
yield i
yield "The strings are:"
comma = False
for t in s:
if comma:
yield ','
else:
comma = True
yield t
如果我使用生成器表达式和
itertools 模块,我最终得到类似:
from itertools import *
def generator2(a, b):
return (z for i, s, c in izip(a, b, count())
for y in (("First line" if c == 0 else "Some later line",),
("The parameter vanishes.",) if i == 0
else ("The parameter is:", i),
("The strings are:",),
islice((x for t in s for x in (',', t)), 1, None))
for z in y)
示例
>>> a = (1, 0, 2), ("ab", "cd", "ef")
>>> print([x for x in generator(a, b)])
['First line', 'The parameter is:', 1, 'The strings are:', 'a', ',', 'b', 'Some later line', 'The parameter vanishes.', 'The strings are:', 'c', ',', 'd', 'Some later line', 'The parameter is:', 2, 'The strings are:', 'e', ',', 'f']
>>> print([x for x in generator2(a, b)])
['First line', 'The parameter is:', 1, 'The strings are:', 'a', ',', 'b', 'Some later line', 'The parameter vanishes.', 'The strings are:', 'c', ',', 'd', 'Some later line', 'The parameter is:', 2, 'The strings are:', 'e', ',', 'f']
这可能比我的第一个解决方案更优雅,但它看起来像是一段只写一次,以后不理解的代码。我想知道这种编写生成器的方式是否有足够的优势让人们这样做。
P.S.:我想我对函数式解决方案的部分问题是,为了尽量减少 Python 中的关键字数量,一些关键字如“for”、“if”和“else”已被回收用于表达式,所以它们在表达式中的位置需要习惯(生成器表达式中的排序 z for x in a for y in x for z in y 至少在我看来,不如经典 for 循环中的排序:for x in a: for y in x: for z in y: yield z)。
【问题讨论】:
-
P.S.:我刚刚发现我必须坚持使用生成器功能。它可以做一件事,我不能用生成器表达式做,即捕获异常。