Apuntes_Python/02_conceptos/14_generators/README.md
2022-12-24 22:41:20 -03:00

148 lines
3.0 KiB
Markdown

# 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("")
```