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 некоторые перечислители не отвечают на перемотку, поэтому они вызывают исключение при вызове этого метода).