Ruby生成器与Python生成器
我一直在研究Ruby和Python中的生成器(在Ruby中称为Enumerators
)之间的相似之处和不同之处,感觉它们基本上是等价的。
不过,我注意到一个不同点,那就是Python的生成器支持一个close()
方法,而Ruby的生成器却不支持。从Python的文档来看,close()
方法的作用是:
在生成器函数暂停的地方引发一个GeneratorExit。如果生成器函数随后引发StopIteration(正常退出或已经关闭)或GeneratorExit(没有捕获这个异常),那么close就会返回给调用它的地方。
那么,Ruby的Enumerators
不支持close()
方法是有什么特别的原因吗?还是说这是个意外的遗漏?
我还发现Ruby的Enumerators
支持rewind()
方法,而Python的生成器却不支持……这也是有什么原因吗?
谢谢!
3 个回答
Ruby中的Enumerator内部使用了一个叫做StopIteration的类,具体可以参考这个链接:Ruby 1.9.1中的Enumerator是如何工作的?
(如果你在使用每个元素的循环时,它会被包装起来)。所以我觉得它们是比较接近的。不过,我不太确定在一个enumerator上,close方法应该具体做什么……也许是清理一些东西?(Python的生成器可能会受益于一个重置功能——需要注意的是,在Ruby中,有些enumerator不支持重置,所以当你调用这个方法时,它会抛出一个异常)。
生成器是基于栈的,而Ruby的枚举器通常是在解释器层面上进行特殊处理的,不是基于栈的。
关于这个rewind方法的文档,信息有点少。不过,要想“重新开始”,生成器需要做两件事中的一件:
- 记住它之前的所有输出,回放这些输出,然后继续之前的工作
- 重置内部状态,以便在没有其他不必要副作用的情况下重复相同的输出
第二种方法并不总是可行;比如说,如果生成器从网络发出字节缓冲区,那么输出就不仅仅依赖于内部状态了。不过,使用第一种方法的生成器在使用过程中必须在内存中不断增加更大的缓冲区。这种生成器在性能上对列表的优势不大。
因此,我得出的结论是,Ruby的rewind
方法应该是可选的,并不是所有具体的枚举类都支持这个方法。所以如果Python的设计者重视里氏替换原则,那么他们就不会要求所有生成器都必须有这个方法。