""" 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 "", line 1, in # 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) # 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))