Generador de aprendizaje de Python

Parte 1: definición del generador

Un generador es un tipo especial de función que genera un valor a la vez. Puedes pensarlo como una función recuperable. Llamar a esta función devolverá un generador que se puede utilizar para generar valores continuos de x [Generador]. En pocas palabras, durante la ejecución de la función, la declaración de rendimiento devolverá el valor que necesita al lugar donde se llama el generador, y luego saldrá de la función. Cuando la función del generador se llama una vez, se ejecuta desde el lugar donde se interrumpió la última vez, y todos los parámetros variables en el generador se guardarán para el próximo uso. --------- De la Enciclopedia Baidu ¡
Luego, lentamente entendemos qué es un generador!

Segunda parte: reserva de conocimiento

Generador de lista

1 Veamos el
código de ejemplo del generador de listas

a=[i for i in range(10)]  ###括号和括号内的内容构成一个列表生成器
print(a)                  ###打印整个生成的列表
print(a[0],a[1],a[2])     ###选择打印列表中的内容

Resultado de ejecución

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
0 1 2

Análisis:
Primero, generamos una lista a usando el generador de listas. Podemos ver el contenido de toda la lista a. También podemos usar fragmentos o subíndices para obtener el valor de una ubicación específica.
Entonces, ¿qué significa esto?
Significa que cuando usamos el generador de listas para generar una lista, el generador de listas ha creado un espacio de memoria en la memoria para nosotros y coloca el valor que queremos obtener en el espacio de memoria. Es decir, ¡ya ha ocupado nuestro espacio de memoria!
El ejemplo que probamos es muy pequeño. Si queremos generar una lista muy grande, por ejemplo, para almacenar 100 millones de números en esta lista, en primer lugar, ocupará mucha memoria y consumirá una cierta cantidad de tiempo. ¡Causará un problema de mala experiencia!
Echemos un vistazo al
código de efecto.

import time
start_time=time.time()
a=[i for i in range(10000000)]
end_time=time.time()
print("time cost : {}" .format(end_time-start_time) )

Resultado de ejecución

time cost : 0.8008153438568115

Cuando queremos generar una lista de 10,000,000 números, la velocidad de finalización ha alcanzado 0.8S, ¡lo cual debería considerarse una experiencia de espera relativamente mala!
Y cuando un número ingresado es mayor que los datos anteriores, puede ocurrir un error, debido al límite de memoria, la capacidad de la lista también debe ser limitada

Y si usa un generador, la eficiencia será mucho mejor. A continuación, comencemos a entender formalmente qué es un generador

Parte 3: generador

1. Generador de reconocimiento preliminar

Combinando los ejemplos que dimos anteriormente, podemos saber que el uso del generador de listas puede crear directamente una lista, pero estará limitada por la memoria, la longitud de la lista será limitada y causará una gran pérdida de recursos. Supongamos que creamos un Solo queremos usar los primeros elementos de la lista, los elementos generados después son indudablemente inútiles

Para hacer frente a esta situación, necesitamos una herramienta muy importante en Python, ¡el generador!

La razón por la cual el generador puede resolver este problema es porque el generador crea una lista, pero no abre inmediatamente el espacio de memoria en la memoria y almacena el valor, sino solo cuando se llama al generador Genere el valor correspondiente, esto sin duda maximizará el uso de los recursos de memoria, ¡y no habrá ningún problema de tiempo de ejecución demasiado largo!

Veamos un ejemplo.

Código

a=(i for i in range(10))    ###()及里边的内容就可以看作一个生成器
print(a)
print(a[0],a[1],a[2])

Resultado de ejecución

Traceback (most recent call last):
<generator object <genexpr> at   0x000001C71A4A1E40> ###print(a)生成的结果
  File "C:/Users/fuxiangyu/PycharmProjects/fuxiangyu/基础实验/标准输出.py", line 3, in <module>
    print(a[0],a[1],a[2])
TypeError: 'generator' object is not subscriptable

Análisis: Podemos ver que cuando queremos imprimir la lista generada, se produce un error.
La primera salida es <objeto generador en 0x000001C71A4A1E40>, lo que indica que esta es una dirección de memoria, ¡y el generador está almacenado!
Luego, cuando queremos imprimir un [0], un [1], un [2], obtenemos un error, el error muestra que el generador no es accesible usando subíndices

En este momento, se hace eco de lo que dijimos. El generador no abre directamente el espacio y asigna valores en la memoria, sino que almacena un generador en la memoria. Cuando queremos usarlo, realizaremos la generación Datos requeridos

Veamos un ejemplo de un generador simple.

a=(i for i in range(10))
for i in range(10):
  print(a.__next__())

或者

a=(i for i in range(10))
print(a.__next__())
print(a.__next__())
print(a.__next__())
print(a.__next__())
print(a.__next__())
print(a.__next__())
print(a.__next__())
print(a.__next__())
print(a.__next__())
print(a.__next__())

0
1
2
3
4
5
6
7
8
9

Ejemplo de comparación con el tiempo de cálculo de la lista generada anteriormente

import time
start_time=time.time()
a=(i for i in range(10000000))
end_time=time.time()
print("time cost : {}" .format(end_time-start_time) )

time cost : 0.0

A través de los dos ejemplos anteriores, podemos refinar los mencionados anteriormente nuevamente, y podemos obtener las siguientes conclusiones finales

1. El generador no abre el espacio en la memoria directamente, sino que coloca un generador en el espacio de la memoria. Solo cuando lo llamamos, el generador generará el resultado que queremos
2. Y la ejecución de todo el generador Se puede entender que hay un puntero (consulte el primero de los dos ejemplos anteriores). El puntero solo registra la posición actual. Cuando usamos la función next (), el puntero se moverá (el generador continúa funcionando), es decir ¡El generador solo registra la posición actual!

Hay dos formas
de usar el generador. Una es que primero usemos a = (i para i en el rango (10)) para generar una lista. La
otra es agregar rendimiento a la función para hacer que toda la función cambie. En un generador

Entonces, ¿por qué el generador tiene tal efecto? ¿Cómo escribimos un generador? Resolvamos las dudas de todos juntos

2. Ejemplos de generador ----- use el generador para lograr concurrencia bajo un solo hilo

Primero, ¡hablemos de por qué el generador tiene tal efecto! Esto se debe a que existe una función de rendimiento. Para obtener una explicación detallada sobre el rendimiento, estudie detenidamente en https://blog.csdn.net/qq_33472765/article/details/80839417 .
Simplemente puede comprender que el rendimiento es un generador en Python. Cuando usa un rendimiento, la función correspondiente es un generador . La función del generador es realizar un procesamiento iterativo en el área de rendimiento. (Hablaremos sobre el problema de iteración más adelante)

A continuación se muestra un ejemplo interesante para ayudarlo a comprender el generador en profundidad. El
escenario es el siguiente: Use el generador para implementar un proceso de hacer bollos y comer bollos
1. Implemente el
código de bollos de comer

def consumer(name):
  print("%s 准备吃包子了"%name)
  while True: 
    type=yield              ###生成器中最重要的一环
    print("包子[%s]来了,被[%s]吃了!"%(type,name))

c=consumer("fuxiangyu")
c.__next__()
c.__next__()
c.__next__()

Resultado de ejecución

fuxiangyu 准备吃包子了
包子[None]来了,[fuxiangyu]吃了!
包子[None]来了,[fuxiangyu]吃了!

Análisis: Analicemos cómo funciona todo el proceso.
Primero, definimos un generador que come bollos. La primera función next (), ejecuta print ("% s está listo para comer bollos"% name) y luego se detiene. En este momento, llamamos nuevamente a la función next (), ejecutó la impresión ("bun [% s] vino, fue comido por [% s]!"% (Tipo, nombre)) este comando, e ingresó nuevamente. Bucle, espere hasta que encuentre el rendimiento nuevamente, pare nuevamente, y luego repita la última operación desde llamar a la función next (), hasta que se detenga el rendimiento, y luego espere la llamada de la función next ()

El rendimiento es equivalente a un nodo y una variable. Cuando el programa se ejecuta para rendir, la ejecución se detiene, y también puede asignar un valor a ceder para que produzca lo que queremos que produzca.

2. Optimización de comer la función de envío de bollos

def consumer(name):
  print("%s 准备吃包子了"%name)
  while True:
    type=yield
    print("包子[%s]来了,被[%s]吃了!"%(type,name))

c=consumer("fuxiangyu")
c.__next__()
c.send("韭菜馅的")
c.send("白菜馅的")
fuxiangyu 准备吃包子了
包子[韭菜馅的]来了,[fuxiangyu]吃了!
包子[白菜馅的]来了,[fuxiangyu]吃了!

¡Así que hemos completado una función de generador que come bollos! A continuación, continuamos completando la función de hacer bollos para lograr la ejecución paralela en un solo hilo

Código

def consumer(name):
  print("%s 准备吃包子了"%name)
  while True:
    type=yield
    print("包子[%s]来了,被[%s]吃了!"%(type,name))

def producer():
   c = consumer("fuxiangyu")
   c.__next__()
   while True:
    type=input("what type would you like:")
    print("we make a baozi  that the type is {}".format(type))
    c.send(type)

producer()

Resultado de ejecución

fuxiangyu 准备吃包子了
what type would you like:韭菜
we make a baozi  that the type is 韭菜
包子[韭菜]来了,[fuxiangyu]吃了!
what type would you like:白菜
we make a baozi  that the type is 白菜
包子[白菜]来了,[fuxiangyu]吃了!
what type would you like:三鲜
we make a baozi  that the type is 三鲜
包子[三鲜]来了,[fuxiangyu]吃了!

Análisis: Hemos definido dos funciones, una es el consumidor del generador y la otra es el productor de la función que llama al generador (se puede ver que hay una demanda del cliente antes de que se produzca). Luego ejecutamos la función de productor.
De acuerdo con la definición en la función de productor (), primero creamos un generador c (la razón por la que necesitamos realizar primero la función next () es permitirle alcanzar primero el rendimiento y hacer una pausa en el rendimiento)
y luego los parámetros Pasado al generador a través de la función send (), el rendimiento en el generador comienza a ejecutarse después de recibir la variable, hasta que encuentra el rendimiento, salta del generador, vuelve a la función original y continúa ejecutándose.

Esto logra la concurrencia bajo un solo hilo, porque en la vista de nuestros usuarios, las funciones de productor () y consumidor () se ejecutan al mismo tiempo. Por supuesto, en realidad se ejecutan en serie, pero el cambio del orden de ejecución nos hace sentir como una ejecución paralela

¡Espero que este pequeño ejemplo pueda profundizar su comprensión del generador! ! !
¡Luego tendremos un concepto que está estrechamente relacionado con el productor, el iterador!

Parte IV: iterar objetos e iteradores

1. ¿Qué es iterar?
Iterar es el proceso de usar operaciones de valor en Python con un bucle for
1. Lo que es un objeto iterable (Iterable) es
fácil de entender: lo que puede completar la declaración del bucle for es el objeto iterativo, como List, tuple, dict, set, str, etc. son todos objetos iterativos, y los iteradores también son objetos iterativos, porque los iteradores también se pueden atravesar a través de un bucle for

El método para juzgar si un objeto es un objeto iterativo:
(1) Si hay un método __iter__ en su método de uso, entonces él es un objeto iterativo

2. ¿Qué es un iterador
? Los iteradores pueden considerarse como un subconjunto de objetos iterativos.

Determine si un objeto es un iterador
(1) Si hay métodos __siguiente__ en su método de uso, entonces es un iterador

Publicado 24 artículos originales · ganó 10 · vistas 2370

Supongo que te gusta

Origin blog.csdn.net/flat0809/article/details/103045690
Recomendado
Clasificación