如何反转一个itertools.chain对象?
我的函数创建了一串生成器:
def bar(num):
import itertools
some_sequence = (x*1.5 for x in range(num))
some_other_sequence = (x*2.6 for x in range(num))
chained = itertools.chain(some_sequence, some_other_sequence)
return chained
有时候,我的函数需要把这个chained
的顺序反过来。简单来说,我想做到的就是下面这样的:
if num < 0:
return reversed(chained)
return chained
可是:
>>> reversed(chained)
TypeError: argument to reversed() must be a sequence
我有哪些选择呢?
这是一些实时图形渲染的代码,所以我不想让它变得太复杂或慢。
编辑: 当我第一次提出这个问题时,我没有考虑到生成器的可逆性。正如很多人指出的,生成器是不能反向操作的。
我其实想要反转的是链条中展开的内容,而不仅仅是生成器的顺序。
根据大家的反馈,我发现没有一个简单的方法可以直接反转一个itertools.chain,所以我觉得在反转的情况下,唯一的解决办法就是使用列表,可能在两种情况下都需要这样做。
7 个回答
4
itertools.chain 这个工具需要实现 __reversed__()
方法(这样最好),或者实现 __len__()
和 __getitem__()
方法。
但是它并没有这样做,而且你也无法直接访问内部的序列,所以你需要把整个序列展开才能反转它。
reversed(list(CHAIN_INSTANCE))
如果 chain 能在所有序列都可以反转的时候提供 __reversed__()
方法,那就太好了,但目前它并没有这样做。也许你可以自己写一个可以反转的 chain 版本。
11
根据定义,生成器是不能反向操作的。生成器的接口是迭代器,这种迭代器只能向前遍历,不能往回走。如果你想要反向遍历一个迭代器,你必须先把它的所有项目都收集起来,然后再进行反向操作。
可以考虑使用列表,或者从开始就生成反向的序列。
12
if num < 0:
lst = list(chained)
lst.reverse()
return lst
else:
return chained
reversed()
这个函数需要一个真正的序列,因为它是通过索引反向遍历的,而生成器(generator)只知道“下一个”项,所以用在生成器上是行不通的。
因为你反转的时候反正需要把整个生成器展开,所以最有效的方法是先把它读成一个列表,然后用 .reverse()
方法在原地反转这个列表。