2010-09-25 15 views
20

He estado investigando las similitudes/diferencias entre los generadores Ruby y Python (conocidos como Enumerators en Ruby), y hasta donde puedo decir que son prácticamente equivalentes.Generadores de Ruby vs generadores Python

Sin embargo, una diferencia que he notado es que los generadores de Python admiten un método close(), mientras que los generadores de Ruby no lo hacen. A partir de los documentos de Python se dice que el método close() para hacer lo siguiente:

plantea una GeneratorExit en el punto donde se ha detenido la función de generador. Si la función de generador de entonces plantea StopIteration (saliendo normalmente, o debido a que ya se están cerrados) o GeneratorExit (por no agarrar la excepción), los rendimientos cercanos a su llamador."

¿Hay una buena razón por Rubí Enumerators no son compatibles con el método close()? ¿O es una omisión accidental ?

también descubrí que Ruby Enumerators apoyo un método rewind() todavía generadores de Python no lo hacen ... ¿hay alguna razón para esto también?

Gracias

+0

Curioso, pero no entiendo cómo usarías esto: ¿puedes dar un ejemplo? –

+5

@Andrew Vit: esto se puede utilizar para hacer que los recursos (conexiones de base de datos, archivos, etc.) que contiene el generador se limpien.También evitará más llamadas a sus métodos 'next' o' send' de otras partes del código. Por ejemplo, puede llamar a 'cerrar' para indicar a uno de varios consumidores que indique a otros que se ha encontrado un valor deseado. – intuited

+0

@intuited, ¿se usa comúnmente el término 'close()' de Python? Creo que leí en algún lado que la comunidad de Python lo considera "arcano" y que realmente no lo utilizan. – horseyguy

Respuesta

2

Los generadores están basados ​​en la pila, los Enumeradores de Ruby son a menudo especializados (a nivel de intérprete) y no basados ​​en la pila.

1

clase de uso StopIteration de Ruby enumerador internamente, véase How do Enumerators work in Ruby 1.9.1?

(se acaba de terminar si lo usa en una para cada llamada). Entonces diría que son bastante cercanos. Dicho esto, no estoy seguro de qué método más cercano en un enumerador debería hacer, exactamente ... ¿limpieza, quizás? (Los generadores de Python probablemente se beneficiarían de un rebobinado, tenga en cuenta que en Ruby, algunos enumeradores no responden al rebobinado, por lo que plantean una excepción cuando llama a ese método).

+2

gracias por su respuesta. Pero 'StopIteration' es lo que Python también usa, de hecho Ruby tomó esta idea de Python jeje. En cuanto a lo que puede hacer un 'close()', mira el comentario de intuited a mi pregunta (arriba). – horseyguy

+0

sí, el Enumerador de Ruby 1.9.x básicamente lo alineó con el Generador de Python (aunque también puedes usar un bloque en Ruby para simular un generador, realmente). – rogerdpack

6

Este documentation for the rewind method es un poco escaso en los detalles. Sin embargo, con el fin de "empezar de nuevo" el generador tendría que hacer una de dos cosas:

  • recordar su salida completa, repetir que la producción una vez que rebobina, a continuación, reanudar lo que estaba haciendo antes
  • restablecer su estado interno de una manera que hace que la misma salida se repita sin otros efectos secundarios no deseados

El segundo de estos no siempre es posible; por ejemplo, si el generador emite buffers de byte desde la red, la salida no es completamente una función del estado interno. Pero cualquier generador que utilice la primera técnica debe necesariamente crear un búfer cada vez más grande en la memoria a medida que se utiliza. Dichos generadores ofrecen pocos beneficios de rendimiento sobre las listas.

Por lo tanto, llego a la conclusión de que el método Ruby rewind debe ser opcional y no siempre es compatible con una clase concreta de enumerador. Entonces, si los diseñadores de Python valoran el Liskov substitution principle, eso los llevaría a no requerir tal método en todos los generadores.

Cuestiones relacionadas