【问题标题】:Ruby generators vs Python generatorsRuby 生成器与 Python 生成器
【发布时间】:2011-04-17 05:21:34
【问题描述】:

我一直在研究 Ruby 和 Python 生成器(在 Ruby 中称为 Enumerators)之间的相似之处/不同之处,据我所知,它们几乎是等价的。

然而,我注意到的一个区别是 Python 生成器支持 close() 方法,而 Ruby 生成器不支持。在 Python 文档中,close() 方法据说执行以下操作:

在生成器函数暂停的位置引发 GeneratorExit。如果生成器函数随后引发 StopIteration(通过正常退出,或由于已被关闭)或 GeneratorExit(通过未捕获异常),则 close 返回其调用者。"

Ruby Enumerators 不支持 close() 方法有充分的理由吗?或者是偶然的 遗漏?

我还发现 Ruby Enumerators 支持 rewind() 方法,但 Python 生成器不支持...这也有原因吗?

谢谢

【问题讨论】:

  • 很好奇,但我不明白你会如何使用它:你能举个例子吗?
  • @Andrew Vit:这可用于清理生成器持有的资源——数据库连接、文件等。它还将阻止从代码的其他部分对其nextsend 方法的任何进一步调用。例如,您可以调用close,从众多消费者中的一个指示其他消费者已找到所需的值。
  • @intuited,Python 的close() 实际上是常用的吗?我想我在某处读到它被 python 社区认为是“神秘的”并且没有真正使用。
  • close() 是 API 的一部分,用于与生成器进行双向通信,将其变成“协程”。您可以在python.org/dev/peps/pep-0342 中阅读有关它的信息。 Ruby 有这个概念吗?

标签: python ruby generator enumerator


【解决方案1】:

这个documentation for the rewind method 有点缺乏细节。但是为了“重新开始”,生成器必须做以下两件事之一:

  • 记住它的完整输出,倒带后重复该输出,然后恢复之前的操作
  • 重置其内部状态,从而导致重复相同的输出而不会产生其他不必要的副作用

其中第二个并不总是可能的;例如,如果生成器从网络发出字节缓冲区,则输出不完全是内部状态的函数。但是任何使用第一种技术的生成器都必须在使用时在内存中建立一个越来越大的缓冲区。与列表相比,此类生成器几乎没有性能优势。

因此,我得出结论,Ruby rewind 方法必须是可选的,并不总是由具体的枚举器类支持。因此,如果 Python 设计者重视 Liskov substitution principle,那将导致他们不需要在所有生成器中都使用这种方法。

【讨论】:

    【解决方案2】:

    生成器是基于堆栈的,Ruby 的枚举器通常是专用的(在解释器级别)而不是基于堆栈的。

    【讨论】:

      【解决方案3】:

      Ruby 的 Enumerator 内部使用 StopIteration 类,见How do Enumerators work in Ruby 1.9.1?

      (如果您在每次调用中使用它,它就会被包装起来)。所以我会说他们是相当接近的。话虽如此,我不确定枚举器上的 close 方法应该做什么,确切地说......也许是清理? (Python 的生成器可能会从 rewind 中受益——请注意,在 Ruby 中,一些枚举器不会响应 rewind,因此当您调用该方法时它们会引发异常。

      【讨论】:

      • 感谢您的回答。但是StopIteration 也是 python 使用的——实际上 Ruby 是从 Python 中得到这个想法的,呵呵。至于close() 可能会做什么,请查看直觉对我的问题的评论(上图)。
      • 是的 ruby​​ 1.9.x 的 Enumerator 基本上使它与 Python 的 Generator 保持一致(尽管您也可以只使用 Ruby 中的块来模拟生成器,真的)。
      猜你喜欢
      • 2013-10-02
      • 2016-12-16
      • 2018-02-01
      • 2015-06-23
      • 2010-12-27
      • 1970-01-01
      • 1970-01-01
      • 2018-11-01
      • 1970-01-01
      相关资源
      最近更新 更多