Ruby генераторы против генераторов Python

Я исследовал сходства / различия между генераторами Ruby и Python (известный как Enumerators в Ruby), и, насколько я могу судить, они в значительной степени эквивалентны.

Однако я заметил одно отличие в том, что Python Generators поддерживают close() метод, тогда как Ruby Generators нет. Из документов Python close() Метод, как говорят, делает следующее:

Вызывает GeneratorExit в точке, где функция генератора была приостановлена. Если функция генератора затем вызывает StopIteration (путем обычного выхода или из-за того, что оно уже закрыто) или GeneratorExit (не перехватывая исключение), close возвращает его вызывающему."

Есть ли веская причина, почему Ruby Enumerators не поддерживает close() метод? Или это случайное упущение?

Я также обнаружил, что Руби Enumerators поддерживать rewind() метод все же генераторы Python не... есть ли причина для этого тоже?

Спасибо

3 ответа

Эта документация для метода перемотки немного ограничена в деталях. Но для того, чтобы "начать все сначала", генератор должен был сделать одну из двух вещей:

  • запомните его полный вывод, повторите этот вывод после перемотки, затем возобновите то, что он делал раньше
  • сбросить его внутреннее состояние таким образом, что тот же вывод будет повторяться без других нежелательных побочных эффектов

Второе из них не всегда возможно; например, если генератор испускает байтовые буферы из сети, выходные данные не полностью зависят от внутреннего состояния. Но любой генератор, который использует первую технику, должен обязательно создавать больший и больший буфер в памяти, как он используется. Такие генераторы предлагают небольшое преимущество в производительности по сравнению со списками.

Поэтому я делаю вывод, что Рубин rewind Метод должен быть необязательным и не всегда поддерживается конкретным классом перечислителя. Так что, если разработчики Python ценят принцип подстановки Лискова, это привело бы к тому, что им не требуется такой метод во всех генераторах.

Генераторы основаны на стеке, перечислители Ruby часто специализированы (на уровне интерпретатора) и не основаны на стеке.

Внутренний Ruby's Enumerator использует класс StopIteration, см. Как работают перечислители в Ruby 1.9.1?

(он просто оборачивается, если вы используете его для каждого вызова). Так что я бы сказал, что они довольно близко. При этом я не уверен, что должен делать метод close на перечислителе, точно... возможно, очистка? (Генераторы Python, вероятно, выиграют от перемотки - обратите внимание, что в Ruby некоторые перечислители не отвечают на перемотку, поэтому они вызывают исключение при вызове этого метода).

Другие вопросы по тегам