Sintaxis de `for` de Python: código de bloque frente a expresiones generadoras de una sola línea

Estoy familiarizado con el bucle for en un contexto de código de bloque. p.ej:

 for c in "word": print c 

Acabo de encontrar algunos ejemplos que usan for diferente. En lugar de comenzar con la instrucción for , la etiquetan al final de una expresión (y no implican un bloque de código con sangría). p.ej:

 sum(x*x for x in range(10)) 

¿Alguien puede señalarme alguna documentación que describa este uso for ? He podido encontrar ejemplos, pero no explicaciones. Toda la documentación que he podido encontrar describe el uso anterior (ejemplo de código de bloque). Ni siquiera estoy seguro de cómo llamar a este uso, así que me disculpo si el título de mi pregunta no está claro.

Lo que estás señalando es Generator en Python. Echa un vistazo a: –

Consulte la documentación: – Generator Expression que contiene exactamente el mismo ejemplo que ha publicado.

De la documentación: –

Los generadores son una herramienta simple y poderosa para crear iteradores. Se escriben como funciones regulares pero usan la statement de rendimiento cuando quieren devolver datos. Cada vez que se llama a next (), el generador se reanuda donde lo dejó (recuerda todos los valores de datos y la última instrucción que se ejecutó)

Los generadores son similares a la List Comprehension que utiliza con square brackets lugar de brackets , pero son más eficientes en memoria. No devuelven la list completa de resultados al mismo tiempo, pero devuelven el objeto generador. Cada vez que invoca next() en el objeto generator , el generador usa el yield para devolver el siguiente valor.

List Comprehension de la List Comprehension para el código anterior se vería así:

 [x * x for x in range(10)] 

También puede agregar condiciones para filtrar los resultados al final de la para.

 [x * x for x in range(10) if x % 2 != 0] 

Esto devolverá una lista de numbers multiplicados por 2 en el rango de 1 a 5, si el número no es divisible por 2.

Un ejemplo de Generators representan el uso del yield puede ser:

 def city_generator(): yield("Konstanz") yield("Zurich") yield("Schaffhausen") yield("Stuttgart") >>> x = city_generator() >>> x.next() Konstanz >>> x.next() Zurich >>> x.next() Schaffhausen >>> x.next() Stuttgart >>> x.next() Traceback (most recent call last): File "", line 1, in  StopIteration 

Entonces, ves que, cada llamada a next() ejecuta el siguiente yield() en el generator . y al final lanza StopIteration .

Esas son expresiones generadoras y están relacionadas con listas de comprensión.

Las comprensiones de listas permiten la fácil creación de listas. Por ejemplo, si desea crear una lista de cuadrados perfectos, podría hacer esto:

 >>> squares = [] >>> for x in range(10): ... squares.append(x**2) ... >>> squares [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] 

Pero en su lugar podrías usar una lista de comprensión:

 squares = [x**2 for x in range(10)] 

Las expresiones del generador son como las comprensiones de listas, excepto que devuelven un objeto generador en lugar de una lista. Puede iterar sobre este objeto generador de una manera similar a las listas de comprensión, pero no tiene que almacenar toda la lista en la memoria de una vez, como lo haría si creara la lista en una lista de comprensión.

La documentación para las expresiones generadoras se encuentra aquí https://www.python.org/dev/peps/pep-0289/ A continuación se muestra el código que utiliza la expresión generadora.

 list(x**2 for x in range(0,10)) 

Su ejemplo específico se llama una expresión del generador . Las comprensiones de lista , las de diccionario y las de conjunto tienen un significado similar (los diferentes tipos de resultados y las expresiones generadoras son perezosas) y tienen la misma syntax, estando el módulo dentro de otros tipos de corchetes, y en el caso de una comprensión de dict que tiene expr1: expr2 en lugar de una sola expresión (x * x en tu ejemplo).