Python 反向生成器
我正在寻找一种反转生成器对象的方法。我知道如何反转序列:
foo = imap(seq.__getitem__, xrange(len(seq)-1, -1, -1))
但是使用生成器作为输入和反转生成器作为输出(len(seq) 保持不变,因此可以使用原始序列的值)是否可能发生类似的情况?
I'm looking for a way to reverse a generator object. I know how to reverse sequences:
foo = imap(seq.__getitem__, xrange(len(seq)-1, -1, -1))
But is something similar possible with a generator as the input and a reversed generator as the output (len(seq) stays the same, so the value from the original sequence can be used)?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
除了将生成器转换为序列并从中创建迭代器之外,您不能以任何通用方式反转生成器。在计算出较早的项之前,不一定能够知道生成器的较晚的项。
更糟糕的是,在遇到 StopIteration 异常之前,您无法知道生成器是否会遇到 StopIteration 异常,因此无法知道序列中的第一项是什么。
你能做的最好的事情就是编写一个reverse_iterator函数:
编辑:当然,你也可以用基于imap的迭代版本替换reverse,以保存一个列表创建。
You cannot reverse a generator in any generic way except by casting it to a sequence and creating an iterator from that. Later terms of a generator cannot necessarily be known until the earlier ones have been calculated.
Even worse, you can't know if your generator will ever hit a StopIteration exception until you hit it, so there's no way to know what there will even be a first term in your sequence.
The best you could do would be to write a reversed_iterator function:
EDIT: You could also, of course, replace reversed in this with your imap based iterative version, to save one list creation.
reversed(list(input_generator))
可能是最简单的方法。如果不先将所有生成器的值收集到一个序列中,就无法以“相反”顺序获取生成器的值,因为生成第二个项目很可能依赖于第一个项目的生成。
reversed(list(input_generator))
is probably the easiest way.There's no way to get a generator's values in "reverse" order without gathering all of them into a sequence first, because generating the second item could very well rely on the first having been generated.
无论如何,您都必须遍历生成器才能获得第一个项目,因此您不妨列出一个列表。尝试
其中
g
是生成器。也会起作用(我没有检查性能是否有显着差异)。
You have to walk through the generator anyway to get the first item so you might as well make a list. Try
where
g
is a generator.would work as well (I didn't check to see if there is a significant difference in performance).
之前的所有答案都会创建中间副本,从而导致内存使用量大幅增加。
生成器的唯一目的就是避免这种情况。
一般来说,正如其他人所说,不可能反转生成器(因为您必须遍历/迭代整个生成器直到满足停止条件,将输出保存在新创建的对象中并反转该对象/创建一个反转迭代器这个新创建的对象)。
但是,凭借您的特定知识/如果您知道生成器的作用,您有时可以自己编写一个新的、相反的生成器。
例如,要反转普通
enumerate
而无需中间副本,您可以编写:或等效地
查看我的答案 这里了解更多背景信息。
All previous answers create intermediate copies that cause large spikes in memory usage.
The sole purpose of a generator is to avoid that.
In general, as others said, it is impossible to reverse a generator (as you have to walk / iterate though the whole generator until the stop condition is met, save the outputs in a newly created object and reverse this object / create an iterator reversing this newly created object).
But with your specific knowledge / if you know, what the generator does, you can sometimes write a new, reverse, one yourself.
For example, to reverse plain
enumerate
without intermediate copies, you can write:or equivalently
Have a look at my answer here for more context.