157 lines
3.6 KiB
Python
157 lines
3.6 KiB
Python
"""
|
|
GENERADORES
|
|
|
|
Son funciones especiales, devuelven una secuencia de valores, de uno en uno,
|
|
en 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 "pausa" hasta q es
|
|
invocada nuevamente.
|
|
|
|
|
|
Creación
|
|
|
|
Un grador. de nros. 0-9
|
|
"""
|
|
def gen_10():
|
|
for n in range(10):
|
|
yield n
|
|
"""
|
|
Uso, hay q instanciar el generador. Luego usar la funcion __next__()
|
|
al no quedar elementos q iterar, el grador. lanza una excepción StopIteration
|
|
"""
|
|
a_gen_10 = gen_10() # Instancia del generador
|
|
|
|
a_gen_10.__next__() # 0
|
|
a_gen_10.__next__() # 1
|
|
a_gen_10.__next__() # 2
|
|
#a_gen_10.__next__() # 3...9
|
|
#a_gen_10.__next__() # Traceback (most recent call last):
|
|
# File "<stdin>", line 1, in <module>
|
|
# StopIteration
|
|
"""
|
|
Al igual q los iteradores, los gradores. se pueden "consumir" con un ciclo for
|
|
Ej. Generador nros. naturales, infinitos.
|
|
"""
|
|
def naturales():
|
|
n = 1
|
|
while True:
|
|
yield n
|
|
n += 1
|
|
|
|
nats = naturales()
|
|
|
|
"""
|
|
Ej. Sentencia "return" para indicar StopIteration
|
|
"""
|
|
def n_nats(n):
|
|
i = 1
|
|
while True:
|
|
if i > n:
|
|
return
|
|
yield i
|
|
i += 1
|
|
|
|
# Generar los 100 primeros naturales
|
|
|
|
"""
|
|
SIMILAR a las listas por comprensión, solo q estas se escriben entre parntesis
|
|
|
|
# Lista por Comprensión
|
|
"""
|
|
[p for p in range(10) if p % 2 == 0] # [0, 2, 4, 6, 8]
|
|
|
|
# Generador
|
|
|
|
(p for p in range(10) if p % 2 == 0) # <generator object <genexpr> at 0x7fb25c49da50>
|
|
|
|
"""
|
|
UTILES:
|
|
- Trabajando con estructuras infinitas.
|
|
- Trabajando con estructuras con alta carga de memoria, se puede reducir el espacio a revisar
|
|
- Se puede retrasar su calculo hasta último momento para favorecer otros procesos
|
|
|
|
Se puede pasar un argumento en caso de acabar el generador.
|
|
"""
|
|
next(nats, None)
|
|
next(nats, 'ratas')
|
|
|
|
# Envio de objetos a un generador con send() (tb lo hace "generar")
|
|
|
|
def accumulator():
|
|
total = 0
|
|
value = None
|
|
while True:
|
|
# receive sent value
|
|
value = yield total
|
|
if value is None:
|
|
break
|
|
# aggregate values
|
|
total += value
|
|
|
|
generator = accumulator()
|
|
# advance until the first "yield"
|
|
next(generator) # 0
|
|
# from this point on, the generator aggregates values
|
|
generator.send(1) # 1
|
|
generator.send(10) # 11
|
|
generator.send(100) # 111
|
|
|
|
# Calling next(generator) is equivalent to calling generator.send(None)
|
|
# next(generator) # StopIteration
|
|
|
|
# USO DE GENERADORES
|
|
|
|
def gen1000():
|
|
"Genera los pri meros 1000 números."
|
|
|
|
for x in range(1000):
|
|
yield x
|
|
|
|
|
|
primeros1000 = gen1000()
|
|
|
|
for x in primeros1000:
|
|
print(x, end=" - ")
|
|
|
|
|
|
print('\n'*2)
|
|
|
|
def gen_primos(cantidad=1):
|
|
"Generador de números primos."
|
|
|
|
cont = 1
|
|
ls_prim = []
|
|
|
|
# Comienzo ciclo infinito
|
|
while cantidad > cont:
|
|
es_primo = True
|
|
cont += 1
|
|
if len(ls_prim) > 0:
|
|
for primo in ls_prim:
|
|
if cont % primo == 0:
|
|
es_primo = False
|
|
break
|
|
if es_primo:
|
|
ls_prim.append(cont)
|
|
yield cont
|
|
|
|
prim1000prim = gen_primos(1000)
|
|
|
|
for x in prim1000prim:
|
|
print(x, end=" - ")
|
|
|
|
|
|
def num_par(n):
|
|
return (x for x in range(n) if x % 2 == 0)
|
|
|
|
gen = num_par(15)
|
|
|
|
gen.__next__()
|
|
gen.__next__()
|
|
print(list(gen))
|