Python 如何反转itertools.chain对象?

Python 如何反转itertools.chain对象?,python,generator,itertools,Python,Generator,Itertools,My函数创建一个生成器链: 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 我的函数有时需要以相反的顺

My函数创建一个生成器链:

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
我的函数有时需要以相反的顺序返回链接的
。从概念上讲,我希望能够做到以下几点:

if num < 0:
    return reversed(chained)
return chained
我有什么选择

这是一些实时图形渲染代码,所以我不想让它太复杂/太慢

编辑: 当我第一次提出这个问题时,我没有考虑发电机的可逆性。正如许多人指出的那样,发电机是不能反转的

事实上,我确实想扭转链条中扁平的内容;不仅仅是发电机的顺序


根据响应,我无法使用单个调用来反转itertools.chain,因此我认为这里唯一的解决方案是使用列表,至少对于反转的情况,或者两者都使用。

reversed
仅适用于支持
len
和索引的对象。您必须先生成生成器的所有结果,然后再将其包装起来

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

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

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

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
def条(num):
进口itertools
某些_序列=(x*1.5表示范围内的x(num))
some_other_sequence=(x*2.6表示范围内的x(num))
_链列表=[某些_序列,某些_其他_序列]
如果num<0:
列出\u链的\u。反向()
chained=itertools.chain(*链列表)
返回链
如果num<0:
lst=列表(链接)
倒转
返回lst
其他:
返回链
reversed()
需要一个实际的序列,因为它通过索引向后迭代,而这对于生成器(它只有“下一个”项的概念)是不起作用的


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

您无法根据定义反转生成器。生成器的接口是迭代器,迭代器是只支持正向迭代的容器。当您想要反转迭代器时,必须首先收集迭代器的所有项,然后再反转它们


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

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


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

itertools.chain需要实现
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu()(这将是最好的)或
\uuuuuuuuuuuuuuuuuuuuuuuu

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

reversed(list(CHAIN_INSTANCE))

如果chain在所有序列都是可反转的情况下使
\uuuuu reversed\uuuuuuu()
可用,那就太好了,但目前它没有做到这一点。也许你可以编写自己版本的chain,它可以

Hm,我本以为
itertools.islice
加上一个负的步骤就可以了,但事实证明只有正值才对arg到
islice
有效。有趣的问题。不仅仅是
链接的
,还有你的生成器:
>>反向((范围(5)中的x代表x))
TypeError:argument to reversed()必须是一个序列
@jleedev良好点;即使有办法反转itertools.chain,也无法反转生成器。我以前没有意识到这一点,但现在明白了。但是,reversed在完全由列表组成的itertools.chain上也不起作用。是的,但是如果您需要访问一般情况下的最后一项(这意味着reversed),则必须耗尽生成器。如果看不到真正的代码,就不可能提供更好的解决方案。@Ant shang、Jochen Ritzel和其他人都提到过,发电机不能在不耗尽它们的情况下反转。当我提出最初的问题时,我没有考虑到这一点。至少shang的解决方案只在num<0的条件下展开生成器。这会反转链中序列的顺序,而不是序列本身<代码>L1=[1,2,3];L2=[4,5,6]
将这两个链接起来,并反转结果,它是
[6,5,4,3,2,1]
,使用您的解决方案,它将是
[4,5,6,1,2,3]
,不是吗?我认为这是op的意思。没有办法在不耗尽它的情况下反转生成器返回的值的顺序…感谢您的建议。当我提出最初的问题时,我没有考虑到生成器不能反转,所以事实上我想反转链中扁平的内容,而不是链本身中生成器的顺序。实现
\uuuuuuu reversed\uuuuu
的对象也将使用
reversed()
def reversed2(iter):
    return reversed(list(iter))
reversed(list(CHAIN_INSTANCE))
def reversed2(iter):
    return reversed(list(iter))