Generador de Python

Generador de Python


El generador es una herramienta para crear iteradores. Es simple y potente, se define como una función de escritura, pero no es necesario usar la return cuando devuelve datos, sino una declaración de yield .

Función generadora

Una "función" que devuelve datos con una declaración de yield , denominada función de generador. Reescribimos la clase personalizada LessThan en la sección anterior en una función de generador:
In [30]: def lessthan(n): 
    ...:     for i in range(n-1, -1, -1): 
    ...:         yield i 
    ...:          
    ...:

In [31]: for i in lessthan(5): 
    ...:     print(i) 
    ...:
4
3
2
1
0
In [32]: lt = lessthan(3)

## 查看生成器对象的__iter__()和__next__():
In [33]: lt.__iter__?
Signature:      lt.__iter__()
Call signature: lt.__iter__(*args, **kwargs)
Type:           method-wrapper
String form:    <method-wrapper '__iter__' of generator object at 0x7fc048cb8ba0>
Docstring:      Implement iter(self).

In [34]: lt.__next__?
Signature:      lt.__next__()
Call signature: lt.__next__(*args, **kwargs)
Type:           method-wrapper
String form:    <method-wrapper '__next__' of generator object at 0x7fc048cb8ba0>
Docstring:      Implement next(self).
Después de reescribir la clase LessThan con el generador, el código es más compacto y compacto, porque crea automáticamente los __iter__() y __next__() , y el bucle forpuede atravesar el objeto generador.
A continuación, definimos un objeto generador lt , invocamos next() en este objeto generador, y cada vez que se invoca, reanudará la ejecución desde la última vez que lo dejó (es decir, recuerde todos los valores de datos cuando se ejecutó la instrucción por última vez). Se StopIteration error StopIteration cuando el generador genera todos los elementos (el generador termina).
In [53]: lt = lessthan(3)

In [54]: next(lt)
Out[54]: 2

In [55]: next(lt)
Out[55]: 1

In [56]: next(lt)
Out[56]: 0

In [57]: next(lt)
---------------------------------------------------
StopIteration      Traceback (most recent call last)
<ipython-input-37-00f31299a3f9> in <module>
----> 1 next(lt)

StopIteration: 

Resolución del generador

Para implementar algunos generadores simples, podemos usar la forma de una sintaxis similar a un análisis en lugar de una función, y reemplazar los corchetes externos con paréntesis.
Las expresiones de los generadores son más compactas pero menos flexibles que los generadores completos, y son más eficientes en memoria que las comprensiones de listas equivalentes. Por ejemplo, en el siguiente código, cada elemento de mylistgenerado por la expresión de la lista se almacena en la memoria, y mygener generará un elemento en cada iteración. Suponiendo que el número de elementos no sea 10, sino 1 millón o más, la ventaja de memoria del generador será muy obvia.
In [41]: mylist = [i*i for i in range(10)]

In [42]: mylist
Out[42]: [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

In [43]: mygener = (i*i for i in range(10))

In [44]: mygener
Out[44]: <generator object <genexpr> at 0x7fc048be3bf8>
El análisis del generador está diseñado para situaciones en las que el generador será utilizado inmediatamente por la función externa, como por ejemplo:
In [45]: sum(i*i for i in range(10))
Out[45]: 285
El i*i for i in range(10) corchete sum() es un analizador de generador que evita generar una lista y ocupar demasiada memoria.
Del mismo modo, los siguientes ejemplos utilizan el análisis de generador:
xvec = [10, 20, 30]
yvec = [7, 5, 3]
sum(x*y for x,y in zip(xvec, yvec))         # dot product

from math import pi, sin
sine_table = {x: sin(x*pi/180) for x in range(0, 91)}

unique_words = set(word  for line in page  for word in line.split())

valedictorian = max((student.gpa, student.name) for student in graduates)

data = 'golf'
list(data[i] for i in range(len(data)-1, -1, -1))

Resumen

Python proporciona dos formas de implementar generadores:
(1) La función del generador <br /> es sintácticamente similar a la función ordinaria, reemplazando el valor de return con yield lugar del yield ; implementando automáticamente el protocolo del iterador: __iter__() y método __next__() . Cuando no hay ningún valor para devolver, se produce una excepción StopInteration . yielddeclaración de yield suspende el estado de la función del generador para que continúe desde el estado de salida cuando se repite la iteración.
(2) Análisis del generador <br /> Similar al análisis de la lista, reemplazando los corchetes con paréntesis, por lo tanto simplemente implementando un generador simple.
(3) Ventajas del generador <br /> El código es compacto y ahorra memoria. A diferencia de una lista que se puede recorrer varias veces, el generador solo puede recorrerla una vez.

留言