# Generadores Son funciones especiales, devuelven una secuencia de varoles, de uno, por cada llamada. Son una forma sencilla y potente de iterador. Un iterador tiene siempre sus elementos disponibles, un generador los va GENERANDO con un llamado al metodo **`__next()__`** . Con esto se pueden tener generadores, que generen infitinos elementos (ej. nums. naturares). Retornan un resultado con la sentencia "**yield**". Y la funcion queda en espera, hasta que es invocada nuevamente. > ***Son funciones que devuelven un objeto iterable. > Son mas eficientes en uso de memoria, generando los items uno a la vez.*** Ejemplos: - [Creación](https://gitea.kickto.net/devfzn/Apuntes_Python/src/branch/master/02_conceptos/14_generators#creaci%C3%B3n) - [Fuera de rango \*StopIteration\*](https://gitea.kickto.net/devfzn/Apuntes_Python/src/branch/master/02_conceptos/14_generators#valores-fuera-de-rango) - [Ahorro de memoria](https://gitea.kickto.net/devfzn/Apuntes_Python/src/branch/master/02_conceptos/14_generators#ejemplo-de-uso-para-ahorro-de-memoria) - [Fibonacci](https://gitea.kickto.net/devfzn/Apuntes_Python/src/branch/master/02_conceptos/14_generators#ejemplo-secuencia-fibonacci) ---- ## Creación ```python def mi_generador(): yield 1 yield 2 yield 3 g = mi_generador() for i in g: print(i) # 1 # 2 # 3 g2 = mi_generador() print(next(g2)) # 1 print(next(g2)) # 2 ``` También se pueden crear similiar al metodo de comprensión de listas, usando **()** en vez de **[]**. ```python mi_generador = (i for i in range(10) if i % 2 == 0) migenerador3 = (i for i in range(1000000) if i % 2 == 0) #for i in migenerador3: # print(i) #print(list(migenerador3)) # 0 2 4 6 8 milista = [i for i in range(1000000) if i % 2 == 0] print(sys.getsizeof(milista)) # 4,1 MB print(sys.getsizeof(migenerador3)) # 112 B ``` ### Valores fuera de rango Causan una ***excepcion StopIteration*** ```python g3 = mi_generador() print(sum(g3)) # 6 def mi_generador2(): yield 5 yield 2 yield 4 g = mi_generador2() print(sorted(g)) # [2, 4, 5] def cuenta_regres(num): print('Iniciando') while num > 0: yield num num -= 1 cr = cuenta_regres(4) print(next(cr)) print(next(cr)) ``` ### Ejemplo de uso, para ahorro de memoria ```python import sys def primer_n(n): nums = [] num = 0 while num < n: nums.append(num) num += 1 return nums # Función ocupa 8,3 MB de memoria # print(sys.getsizeof(primer_n(1000000))) print(primer_n(10)) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] def primer_n_gen(n): num = 0 while num < n: yield num num += 1 # Función ocupa 112 KB de memoria # print(sys.getsizeof(primer_n_gen(1000000))) print(primer_n(10)) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] ``` ### Ejemplo secuencia fibonacci ```python def fibonacci(limite): "0, 1, 1, 2, 3, 5, 8, 13..." a, b = 0, 1 while a < limite: yield a a, b = b, a + b fibo = fibonacci(300) for i in fibo: print(i, end=" ") print("") ```