11

我的函数创建了一个生成器链:

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,因此我认为这里唯一的解决方案是使用列表,至少对于反向情况,也许两者兼而有之。

4

7 回答 7

12
if num < 0:
    lst = list(chained)
    lst.reverse()
    return lst
else:
    return chained

reversed()需要一个实际的序列,因为它通过索引向后迭代它,这对于生成器(只有“下一个”项目的概念)不起作用。

.reverse()由于无论如何您都需要展开整个生成器以进行反转,因此最有效的方法是将其读入列表并使用该方法就地反转列表。

于 2011-02-15T20:13:02.413 回答
11

根据定义,您不能反转生成器。生成器的接口是迭代器,它是一个只支持前向迭代的容器。当你想反转一个迭代器时,你必须先收集它的所有项目,然后再反转它们。

改用列表或从一开始就向后生成序列。

于 2011-02-15T20:20:10.103 回答
4

itertools.chain 需要实现__reversed__()(这将是最好的)或__len__()__getitem__()

因为它没有,甚至没有办法访问内部序列,您需要扩展整个序列才能反转它。

reversed(list(CHAIN_INSTANCE))

如果链在所有序列都是可逆的时候可用,那就太好__reversed__()了,但目前它不这样做。也许您可以编写自己的链版本

于 2011-02-15T22:40:54.857 回答
1
def reversed2(iter):
    return reversed(list(iter))
于 2011-06-10T04:55:01.077 回答
0

reversed仅适用于支持len和索引的对象。reversed在环绕它们之前,您必须首先生成生成器的所有结果。

但是,您可以轻松地做到这一点:

def bar(num):
    import itertools
    some_sequence = (x*1.5 for x in range(num, -1, -1))
    some_other_sequence = (x*2.6 for x in range(num, -1, -1))
    chained = itertools.chain(some_other_sequence, some_sequence)
    return chained
于 2011-02-15T20:11:11.653 回答
0

这在你真正的应用程序中有效吗?

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))
    list_of_chains = [some_sequence, some_other_sequence]
    if num < 0:
        list_of_chains.reverse()
    chained = itertools.chain(*list_of_chains)
    return chained
于 2011-02-15T20:11:41.047 回答
0

理论上你不能,因为链式对象甚至可能包含无限序列,例如itertools.count(...).

如果适用,您应该尝试反转您的生成器/序列或reversed(iterable)用于每个序列,然后将它们从后到先链接在一起。当然,这在很大程度上取决于您的用例。

于 2011-02-15T20:21:25.370 回答