Qué mágico momento fue el de la explicación del funcionamiento interno del ciclo for! Probablemente ha sido de mis momentos favoritos de la trilogía de FacMartoni
Introducción
¿Qué necesitas saber para tomar el curso?
¿Cómo funciona Python?
Cómo organizar las carpetas de tus proyectos
Static Typing
¿Qué son los tipados?
Tipado estático en Python
Practicando el tipado estático
Conceptos avanzados de funciones
Scope: alcance de las variables
Closures
Programando closures
Decoradores
Programando decoradores
Estructuras de datos avanzadas
Iteradores
La sucesión de Fibonacci
Generadores
Mejorando nuestra sucesión de Fibonacci
Sets
Operaciones con sets
Eliminando los repetidos de una lista
Bonus
Manejo de fechas
Time zones
Conclusión
Completaste la trilogía. ¿Cómo seguir?
Aún no tienes acceso a esta clase
Crea una cuenta y continúa viendo este curso
Aportes 64
Preguntas 10
Qué mágico momento fue el de la explicación del funcionamiento interno del ciclo for! Probablemente ha sido de mis momentos favoritos de la trilogía de FacMartoni
Antes de entender qué son los iteradores, primero debemos entender a los iterables.
Son todos aquellos objetos que podemos recorrer en un ciclo. Son aquellas estructuras de datos divisibles en elementos únicos que yo puedo recorrer en un ciclo.
Pero en Python las cosas no son así. Los iterables se convierten en iteradores.
Ejemplo:
# Creando un iterador
my_list = [1,2,3,4,5]
my_iter = iter(my_list)
# Iterando un iterador
print(next(my_iter))
# Cuando no quedan datos, la excepción StopIteration es elevada
# Creando un iterador
my_list = [1,2,3,4,5]
my_iter = iter(my_list)
# Iterando un iterador
while True: #ciclo infinito
try:
element = next(my_iter)
print(element)
except StopIteration:
break
Momento impactante: El ciclo “for” dentro de Python, no existe. Es un while con StopIteration. 🤯🤯🤯
my_list = [1,2,3,4,5]
for element in my_list:
print(element)
evenNumbers.py
:
class EvenNumbers:
"""Clase que implementa un iterador de todos los números pares,
o los números pares hasta un máximo
"""
#* Constructor de la clase
def __init__(self, max = None): #self hace referencia al objeto futuro que voy a crear con esta clase
self.max = max
# Método para tener elementos o atributos que voy a necesitar para que el iterador funcione
def __iter__(self):
self.num = 0 #Primer número par
#* Convertir un iterable en un iterador
return self
# Método para tener la función "next" de Python
def __next__(self):
if not self.max or self.num <= self.max:
result = self.num
self.num += 2
return result
else:
raise StopIteration
Ventajas de usar iteradores:
EL CLICLO FOR NO EXISTE
Iterables aquellas estructuras de datos divisibles en elementos únicos que se pueden recorrer en un ciclo.
Todos los iterables pueden convertirse en iteradores para poder ser recorridos en un ciclo.
Es un alias de un ciclo While infinito con un Try except que controla el Error StopIteration
Solo tenemos que implementar los métodos
__iter__() :
"El método __iter__() devuelve el objeto iterador en sí. Si es necesario, se puede realizar alguna inicialización."
__next__():
"El método __next__() debe devolver el siguiente elemento de la secuencia.Al llegar al final, y debe subir el error StopIteration."
Es una expresión que explica con obtener el resultado.
Por ello ahorra la memoria y aumenta la velocidad.
Los iteradores son estructuras de datos divisibles en elementos únicos que puedo recorrer en un ciclo.
my_list = [1,2,3]
my_iter= iter(my_list)
#iterando un iterador
print(next(my_iter))
#Cuándo no quedan datos la excepción StopIteration es elevada
# creando un iterador
my_list = [1,2,3,4,5,6]
my_iter = iter(my_list)
#iterando un iterador
while True:
try:
print(next(my_iter))
print(element)
except StopIteration:
break
Resultado de aplicar iter sobre nuestra lista y el ciclo while infinito.
si usamos while true hará un ciclo infinito
Usamos el manejo de errores. Con try usamos el next() para que ejecute el siguiente elemento
except para cuando devuelva el error StopIteration el ciclo se corta con un break
El ciclo for hace lo mismo que el cico while true. en vez de escribir todo ese código se puede resumir en:
for element in my_list:
print(element)
el ciclo for no existe en python, lo que hace python es convertir una iterable en un iterador y con un ciclo while recorrerlo hasta encontrar el StopIteration
El protocolo de los iteradores: para construir un iterador, hay que construir una clase que contenga dos métodos importantes:
__iter__() y __next__()
class EventNumber:
"""
Clase que implementa un iterador de todos los números pares, o los números pares hasta un máximo."""
def __init__(self,max=None):
self.max = max
def __iter__(self):
self.num = 0
return self
def __next__(self):
if not self.max or self.num <= self.max:
result= self.num
self.num += 2
return result
else:
raise StopIteration
__ iter __(): retorna al objeto al en sí mismo. Convierte un iterable en un iterador.
_ next __(): Convierte a la función next. Nos permite extraer cada uno de los elementos del iterador
Con los iteradores trabajamos más rápido y ahorramos memoria
Es una expresi+on que exlica como obtener el resultado. También ahorra memoria y es más rápido
Iterables -> Todos los objetos que podemos recorrer en un ciclo, ejem: una lista, un string
Iteradores -> Ahorra recursos, puedo almacenar secuencias y progreciones matematicas, ocupa poca memoria.
Son una estructura de datos para guardar datos infinitos.
Los iterables son los objetos que podemos recorrer a través de un ciclo dicho de otra manera, son estructuras de datos divisibles en elementos que puedo recorrer en un ciclo.
Todos los iterables pueden convertirse en iteradores. De esta manera es que internamente Python los puede recorrer realmente, esto mediante parsing usando el comando iter.
# Creando un iterador
my_list = [1, 2, 3, 4, 5]
my_iter = iter(my_list)
# Iterando un iterador
print(next(my_iter)) # Next nos permite acceder al siguiente elemento del iterador por cada llamada
# Cuando no quedan datos, la excepción StopIteration es elevada
Si queremos crear un código que nos permita recorrer todos los elementos de nuestra lista usando la función next para como aparece en el ejemplo anterior, tendríamos que realizar un bloque try-except:
# Creando un iterador
my_list = [1, 2, 3, 4, 5]
my_iter = iter(my_list)
# Iterando un iterador
while True:
try:
element = next(my_iter)
print(next(my_iter)) # Next nos permite acceder al siguiente elemento del iterador por cada llamada
except StopIteration:
break # Salimos del ciclo una vez que obtenemos el último valor iterable
Lo anterior es posible hacerlo de una manera mucho más sencilla, mediante el ciclo for el cual es azúcar sintáctica pues facilita y realiza de una manera mas estética y sencilla una operación:
my_list = [1, 2, 3, 4, 5]
for element in my_list
print ("element")
Es posible crear un iterador personalizado (directamente, sin castear/casting) el cual nos permita recorrer un infinito número de elementos de acuerdo a una función dada, utiliza dos métodos internos importantes: “iter” y “next”.
El uso de una función que determina los valores a iterar nos permite ahorrar memoria y trabajar más rápido, pues no tenemos que almacenar cada uno de los valores, sino solo una función para extraer cada uno de los elementos.
El siguiente ejemplo crea un iterador que recorre todos los números pares:
class EvenNumbers:
"""Clase que implementa un iterador de todos los números pares,
o los números pares hasta un máximo que definimos
"""
# Constructor
def __init__(self, max = None): # self = objeto futuro creado con esta clase
self.max = max
# Método para tener elementos o atributos que voy a necesitar para que el iterador funcione
def __iter__(self):
self.num = 0 # Primer número par
return self
# Método para tener la función "next" del ciclo for, es decir, recorrer cada valor.
def __next__(self):
if not self.max or self.num <= self.max:
result = self.num
self.num += 2
return result
else:
raise StopIteration
⭐️⭐️⭐️⭐️⭐️
El ciclo “for” dentro de Python no existe. Es realmente un while con StopIteration.
⭐️⭐️⭐️⭐️⭐️
Si lees esto, pasaste la mitad del curso !!
Animo, falta poco!!
Aprendimos geniales conceptos del lenguaje Python !!! Cada vez me agrada más… y que buen profesor!! para hacer entender estos temas… 🤠🤠
Los iteradores son todos aquellos elementos que podemos recorrer en un ciclo. Por ejemplo, una lista, un string o un diccionario.
Cuando se hace un ciclo, Python internamente no está recorriendo a ese iterable, es decir, el for no funciona directamente como lo vemos en la pantalla, sino que ese iterable se convierte a un objeto especial llamado Iterador. Y es este el que recorre el objeto.
Lo que hace Python internamente:
# Creando iterador
my_list = [1,2,3,4,5]
my_iter = iter(my_list)
# Iterando
print(next(my_iter))
# Cuando no quedan datos, lavanta la expeción StopIteration
Una forma de iterar en un conjunto muy grande:
Un ciclo for no es más que azúcar sintáctica de este proceso. El ciclo for realmente es solo un alias de una iteración.
my_list = [1,2,3,4,5]
my_iter = iter(my_list)
while True:
try:
element = next(my_iter)
print(element)
except StopIteration:
break
El protocolo de los iteradores nos dice que para construir un iterador se necesita una clase que contenga dos métodos: el método iter y el método next .
class EvenNumbers:
"""Clase que implementa un iterador
de todos los números pares o los números
pares hasta un máximo"""
def __init__(self, max = None) -> None:
self.max = max
def __iter__(self):
self.num = 0
return self
def __next__(self):
if not self.max or self.num <= self.max:
result = self.num
self.num += 2
return result
else:
raise StopIteration
El método iter sirve para tener elementos o atributos que se van a necesitar para que el iterador funcione. En este caso, el único atributo necesario son cada uno de los números de esa iteración. Se le asigna el valor inicial de 0 y se retorna al objeto en sí mismo.
El método next es el que se necesita para tener la función next en Python. Este método permite extraer cada uno de los elementos de iterador. En este caso se coloca la condición “si no se definió un self.max (limite) o el número que se está por recorrer es menor o igual a self.max, se le asigna a la variable result el número de la iteración (self.num). Después se le suma dos a self.num y se retorna. Si la condición se cumple se levanta la excepción Stop Iteration”.
Un iterator es una estructura de datos para guardar datos infinitos 🤯. Para entenderlo, primero debemos saber que un iterable es todo aquel objeto que puedo recorrer en un ciclo (lista, strings, etc). Un iterable es divisible.
Cuando hacemos un ciclo, Python internamente no está recorriendo a ese iterable, si no más bien ese iterable se convierte internamente en un iterador, que si puede ser recorrido. 🤔
Para crear un iterador:
# Creando un iterador
my_list = [1, 2, 3, 4, 5]
my_iter = iter(my_list) # Se recibe un iterable
# Iterando un iterador
print(next(my_iter))
# Cuando no quedan datos, la excepción StopIteration es elevada
Para que no se rompa el código, hacemos manejo de errores: 🧠
# Creando un iterador
my_list = [1, 2, 3, 4, 5]
my_iter = iter(my_list)
# Iterando un iterador
while True:
try:
element = next(my_iter)
print(element)
except StopIteration:
break
Esta es una manera eficiente de extraer todos los elementos de un iterable. De hecho, esta es la manera en la que funciona un ciclo for, es la azúcar sintaxis de este código anterior 😍. El ciclo for en si mismo no existe.
¿Cómo construyo un iterador?. Una opción es castear desde un iterable. Para hacerlo desde cero, debemos usar el protocolo de los iteradores que contiene dos clases importantes __iter__
y __next__
:
class EvenNumbers:
"""Calse que implementa un iterador de todos los
números pares, o los números pares hasta un máximo"""
def __init__(self, max = None):
self.max = max
def __iter__(self):
self.num = 0
return self
def __next__(self):
if not self.max or self.num <= self.max:
result = self.num
self.num += 2
return self
else:
raise StopIteration
Las ventajas de usar iteradores: Nos ahorra recursos computacionales y de memoria, ya que tenemos una función matemática de como obtener los siguientes elementos, sin necesidad de guardarlos todos 👀.
Por si alguno se pregunta como usar clases para construir iteradores, aquí va:
Primero se define la clase con sus 3 métodos fundamentales
class EvenNumbers:
"""Clase que implementa un iterador de todos los números pares,
o los números pares hasta un máximo
"""
#* Constructor de la clase
def __init__(self, max = None): #self hace referencia al objeto futuro que voy a crear con esta clase
self.max = max
# Método para tener elementos o atributos que voy a necesitar para que el iterador funcione
def __iter__(self):
self.num = 0 #Primer número par
#* Convertir un iterable en un iterador
return self
# Método para tener la función "next" de Python
def __next__(self):
if not self.max or self.num <= self.max:
result = self.num
self.num += 2
return result
else:
raise StopIteration
Luego, en nuestro archivo principal, importamos la clase creada con el iterador
from EvenNumbers import EvenNumbers
n = EvenNumbers(18) #Instaciamos un objeto
myIter = n.__iter__() #Aplicamos el método __iter__
while True: #ciclo infinito #Utilizamos nuestro for not for
try:
element = n.__next__() #Llamamos al método __next__
print(element)
except StopIteration:
break
For no existe, he vivido en una mentira, noooooooooo, que bueno que tienes que ver dos cursos antes de esta revelación sino te volves [email protected]
Una forma de aplicar la función que el profesor explica con el while infinito es hacer una llamada recursiva a la misma función siempre que no tengamos un error al intentar next().
def loop_iterador(iterador):
iterador = iter(iterador)
try:
print(next(iterador))
except StopIteration:
print('Fin de los elementos del iterador')
else:
return loop_iterador(iterador)
Les comparto como aplicando el concepto de iteradores realice el calculo del número e a través de una suma infinita.
class NumESum():
def __init__(self, iterations: int):
self.iterations = iterations
def __iter__(self):
self.fact = 1
self.sum = 0
if self.iterations <= 0:
self.iterations = -1
self.k = 1
return self
def __next__(self):
self.sum+=self.k**2/(2*self.fact) # sum(k^2/(2*k!)) from k = 1 to ∞
if self.k > self.iterations:
raise StopIteration
else:
self.k += 1
self.fact=self.fact*self.k
return self.sum
if __name__ == "__main__":
for element in NumESum(100): # Ejecutar el algoritmo con 100 interacciones.
print(element)
Plantee otra solución para iterar n elementos.
Con la ayuda de una función recursiva y un decorador.
def iterador(func):
def wrapper(lista):
lista = iter(lista)
func(lista)
return wrapper
@iterador
def iterame(lista):
try:
print(next(lista))
return iterame(lista)
except StopIteration:
pass
iterame('Platzi<3')
raise sin ningún argumento es un uso especial de la sintaxis de python. Significa obtener la excepción y volver a subirla.
Una estructura de datos para guardar datos infinitos.
Un iterable son todos los objetos que podemos recorrer en un ciclo, ejemplo, una lista a la cual puedo acceder a sus elementos con un ciclo for
.
# creando un iterador
my_list = [1,2,3,4,5]
my_iter = iter(my_list)
# iterando un iterador
print(next(my_iter))
# cuando no quedan datos, la excepción StopIteration es elevada
Esta sería la forma de como trabajaría el iterador:
# creando un iterador
my_list = [1,2,3,4,5]
my_iter = iter(my_list)
# iterando un iterador
while True:
try:
element = next(my_iter)
print(element)
except StopIteration:
break
Ya conocemos el azúcar sintáctico para evitar código complejo y ayudarnos con:
for element in my_list:
print(elment)
Cómo construyo un iterador?
Para construir un iterador se necesita saber del protocolo de los iteradores.
El protocolo de los iteradores dice que para construir un iterador tenemos que tener una clase qeu contenga dos metodos importantes __iter__
y __next__
.
class EvenNumbers:
"""Clase que implementa un iterador de todos los números pares,
o los números pares hasta un máximo"""
def __init__(self, max=None):
self.max = max
def __iter__(self):
self.num = 0
return self
def __next__(self):
if not self.max or self.num <= self.max:
result = self.num
self.num += 2
return result
else:
raise StopIteration
Ventajas de usar los iteradores:
Probe con el modulo random para elegir un numero entre 1 y el que seleccione el usuario , esto me da la direfencia de tiempo de ejecucion sobre la base de numeros analizados para elegir el random:
# choose a random element from a list
from random import seed
from random import choice
from datetime import datetime
def execution_time(func): #funcion para determinar el tiempo que una funcion tarda en ejecutarse
def wrapper(*args, **kwargs):
initial_time = datetime.now() #devuelve fecha z hora exactas de cuando se ejecuta la linea
func(*args, **kwargs) #no importa la cantidad de argumentos poscionales o nombrados, la funcion los va a recibir.
final_time = datetime.now()
time_elapsed = final_time - initial_time
print("pasaron "+ str(time_elapsed.total_seconds()) + " segundos")
return wrapper
def random_num(n: int):
sequence = [i for i in range(n)]
selection = choice(sequence)
return(selection)
@execution_time
def run():
print(random_num(int(input("Un numero entre 1 y ....?: "))))
if __name__ == '__main__':
TSSSSSSSAAAAAAAAAAALAAAAAA que no existen los for jajajajaja 🤯🤯🤯
Porque dice dandar iter y dandar next el profesor. 😦
Demasiado pro la manera de explicar, Facundo.
Lit
Este video puede ayudar como repaso de POO
https://youtu.be/VYXdpjCZojA
class EvenNumbers:
"""Clase que implementa un iterador
de todos los numeros pares, o los numeros pares
hasta un maximo dado por el usuario"""
def __init__(self, max=None):
self.max = max
def __iter__(self):
self.num = 0
return self
def __next__(self):
if not self.max or self.num <= self.max:
num = self.num
self.num += 2
return num
else:
raise StopIteration
for i in EvenNumbers(11):
print(i)
VENTAJAS DE USAR ITERADORES
Sucesión de Fibonacci en una lista hasta un valo máximo indicado:
import os
class FiboIter():
number=int(input('enter a number as maximum elemnent of Fibonacci succession : ' ))
def __init__(self,max=number):
self.max = max
def __iter__(self):
self.n1 = 0
self.n2 = 1
self.counter = 0
return self
def __next__(self):
if self.counter== 0:
self.next = []
self.counter +=1
self.next.append(self.n1)
return ' '
elif self.counter == 1:
self.counter +=1
self.next.append(self.n2)
return ' '
else:
# try:
self.aux = self.n1 + self.n2
if self.aux <= self.max:
# self.n1 = self.n2
# self.n2 = self.aux
self.n1, self.n2=self.n2,self.aux
self.counter +=1
self.next.append(self.aux)
# return self.next
return ' '
else:
os.system('clear')
raise StopIteration(print(f'Finonacci Succession:\n{self.next}\nStop Iteration Error: There is not an element higher than {self.max}'))
if __name__ == '__main__':
fibonacci= FiboIter()
for element in fibonacci:
print(element)
woooo esto esta genial
Protocolo de los iteradores
Fact:
También puedes sacar los valores iterables de esta manera
StopIteration
Bueno, ejecutando el iterador creado, por medio de un for.
for num in EvenNumbers(10):
print(num)
MI código de Fibo con limite de 99999:
import time
class FiboIter():
def __iter__(self, max=99999):
self.max = max
self.n1 = 0 #Primer numero de la sucesión
self.n2 = 1 #Segundo número de la sucesión
self.counter = 0
return self
def __next__(self):
if self.counter == 0: #Si estamos en el primer elemento del iterador
self.counter += 1
return self.n1
elif self.counter == 1: #Segunda vuelta del iterador
self.counter += 1
return self.n2
elif not self.max or self.n2 <=self.max :
#Crear atributo auxiliar, que es igual a la suma de los
#dos números anteriores de la sucesion
self.aux = self.n1 + self.n2
#Reasignar valores
#self.n1 = self.n2
#self.n2 = self.aux
#Que también se puedde hacer con SWAP
self.n1, self.n2 = self.n2, self.aux
self.counter += 1
return self.aux
else:
raise StopIteration
if __name__ == '__main__':
#Instanciamos la clase FiboIter() a una variable para poder crear objetos.
fibonacci = FiboIter() #En este punto se crea __iter__
for element in fibonacci: #se ejecuta __next__
print(element)
time.sleep(0.025) #Pausar 0.05 segundos para poder ver más claramente la sucesión.
Deberías de usar el cursor para señalar lo que estás explicando, así no se distingue de que estás hablando
6:07 🤯
Por lo que veo en los comentarios, hay un gran asombro por lo explicado respecto a que el ciclo for no es más que un alias para un while más complejo. Sin embargo, a pesar de ser una buena explicación como método pedagógico, se encuentra lejos de la realidad. De hecho, claro que existen los ciclos for en Python y no son azúcar sintáctica para un while del mismo lenguaje. En Python, los ciclos for son transpilados a lenguaje C (cosa que no ocurre con los ciclos while), por lo que son mucho más eficientes que un ciclo while. Una explicación simple puede ser encontrada en este video de Youtube. Y pueden probar el siguiente código en sus máquinas, viendo que el ciclo for es bastante más rápido que el while (implicando que no puede ser solo azúcar sintáctica).
# for.py
from timeit import default_timer as timer
from datetime import timedelta
def main():
start = timer()
for i in range(100000000):
pass
end = timer()
print(timedelta(seconds=end - start))
if __name__ == "__main__":
main()
# while_iter.py
from timeit import default_timer as timer
from datetime import timedelta
start = timer()
def main():
my_list = range(100000000)
my_iter = iter(my_list)
start = timer()
while True:
try:
element = next(my_iter)
except StopIteration:
break
end = timer()
print(timedelta(seconds=end - start))
if __name__ == "__main__":
main()
# while.py
from timeit import default_timer as timer
from datetime import timedelta
start = timer()
def main():
start = timer()
i = 0
while i < 100000000:
i += 1
end = timer()
print(timedelta(seconds=end - start))
if __name__ == "__main__":
main()
✨Como aplicación del concepto de iteradores hice un rango para floats.
class frange():
"""frange(start, stop, step) -> frange object
Iterates over a range of floats from start(inclusive) to stop(exclusive) by step."""
def __init__(self, *args):
if len(args) == 3:
self.start = args[0]
self.stop = args[1]
self.step = args[2]
elif len(args) == 2:
self.start = args[0]
self.stop = args[1]
self.step = 0.5
elif len(args) == 1:
self.start = 0
self.stop = args[0]
self.step = 0.5
def __iter__(self):
self.__allowed = True
if self.start < self.stop and self.step < 0:
self.__allowed = False
elif self.start > self.stop and self.step > 0:
self.__allowed = False
elif self.start == self.stop:
self.__allowed = False
elif self.step == 0:
self.__allowed = False
self.__current = self.start*1
return self
def __next__(self):
if self.__allowed:
if self.step > 0:
if self.__current + self.step <= self.stop:
self.__aux = self.__current*1
self.__current += self.step
if self.__aux == self.start:
return self.start
else:
return self.__aux
else:
raise StopIteration
else:
if self.__current + self.step >= self.stop:
self.__aux = self.__current*1
self.__current += self.step
if self.__aux == self.start:
return self.start
else:
return self.__aux
else:
raise StopIteration
else:
raise StopIteration
En minuto 12:41 hubo un raise de la voz del profe. (se acabaron las iteraciones a partir de aquí 😦 )
en Python, los iteradores tienen que implementar un método next que debe devolver los elementos, de a uno por vez, comenzando por el primero. Y al llegar al final de la estructura, debe levantar una excepción de tipo StopIteration.
Es decir que las siguientes estructuras son equivalentes
for elemento in secuencia:
# hacer algo con elemento
iterador = iter(secuencia)
while True:
try:
elemento = iterador.next()
except StopIteration:
break
# hacer algo con elemento
En particular, si queremos implementar un iterador para la lista enlazada, la mejor solución implica crear una nueva clase, _IteradorListaEnlazada, que implemente el método next() de la forma apropiada.
Advertencia
Utilizamos la notación de clase privada, utilizada también para la clase _Nodo, ya que si bien se devolverá el iterador cuando sea necesario, un programador externo no debería construir el iterador sin pasar a través de la lista enlazada.
Para inicializar la clase, lo único que se necesita es una referencia al primer elemento de la lista.
class _IteradorListaEnlazada(object):
" Iterador para la clase ListaEnlazada “
def init(self, prim):
”"" Constructor del iterador.
prim es el primer elemento de la lista. “”"
self.actual = prim
A partir de allí, el iterador irá avanzando a través de los elementos de la lista mediante el método next. Para verificar que no se haya llegado al final de la lista, se corroborará que la referencia self.actual sea distinta de None.
if self.actual == None:
raise StopIteration(“No hay más elementos en la lista”)
Una vez que se pasó la verificación, la primera llamada a next debe devolver el primer elemento, pero también debe avanzar, para que la siguiente llamada devuelva el siguiente elemento. Por ello, se utiliza la estructura guardar, avanzar, devolver.
dato = self.actual.dato
self.actual = self.actual.prox
return dato
En el Código 16.4 se puede ver el código completo del iterador.
class _IteradorListaEnlazada(object):
" Iterador para la clase ListaEnlazada “
def init(self, prim):
”"" Constructor del iterador.
prim es el primer elemento de la lista. “”"
self.actual = prim
def next(self):
""" Devuelve uno a uno los elementos de la lista. """
if self.actual == None:
raise StopIteration("No hay más elementos en la lista")
# Guarda el dato
dato = self.actual.dato
# Avanza en la lista
self.actual = self.actual.prox
# Devuelve el dato
return dato
Finalmente, una vez que se tiene el iterador implementado, es necesario modificar la clase ListaEnlazada para que devuelva el iterador cuando se llama al método iter.
def iter(self):
" Devuelve el iterador de la lista. "
return _IteradorListaEnlazada(self.prim)
Con todo esto será posible recorrer nuestra lista con la estructura a la que estamos acostumbrados.
l = ListaEnlazada()
l.append(1)
l.append(3)
l.append(5)
for valor in l:
… print valor
…
1
3
5
Curso muy bueno y profesor 10/10.
#Ejercicio para poner a prueba el concepto de decorador
#programa para decorar listas, si el elemento es un entero lo multiplicamos por 2
#Si es un string lo pasamos a mayuscula
def decorator(function):
def wrapper(lista):
j=0
for i in lista:
if type(i)==str:
lista[j]=i.upper()
elif type(i)==int:
lista[j]=i*2
j+=1
return function(lista)
return wrapper
@decorator
def lista_decorada(lista):
return lista
lista=[5,“herman”,8,9,“hola”]
print(lista_decorada(lista))
Entendido, a practicar
Con esta clase pude entender mucho mejor el ciclo for. Admito que quedé impresionado cuando explicó todo el funcionamiento interno jaja. ¡Brutal!
Los iteradores son eficientes porque en vez de almacenar datos saben como generar el siguiente, en pocas palabras no necesitan almacenar toda la información pues saben como construirla mediante las instrucciones que se le hayan dado
Eso del ciclo for me dejo sorprendido de las cosas que uno aprende en Platzi con estos geniales cursos
🤯
Ahora a ver el curso de POO
Queeeeeeeeeeeeeeeeeeeeeeeeeeee no existe el FOR en python
Aquí una explicación que también podría ayudar iteradores
🤯
el ciclo for como tal no existe es un alias del while
Si lees esto, pasaste la mitad del curso!!
Animo, falta poco!!
iteradores:
Una estructura de datos para guardar datos infinitos
Me ha gustador mucho esta clase, se comprende lo que significa la exploración de Python a fondo.
Los ciclos for son los papás.
Esto de los metodos iter y next es todo un negocio del cruel del imperialismo.
Metodo __next__
>>> 🟢 JPEG is also a mathematical formula 📝
ame esta clase!
mi solución
import time
def fibo_gen(stop = None):
n1 = 0
n2 = 1
counter = 0
while True:
if stop == counter:
break
if counter == 0:
yield n1
elif counter == 1:
yield n2
else:
aux = n1 + n2
n1, n2 = n2, aux
yield aux
counter += 1
if __name__ == "__main__":
fibonacci = fibo_gen()
for element in fibonacci:
print(element)
time.sleep(0.5)
¿Quieres ver más aportes, preguntas y respuestas de la comunidad? Crea una cuenta o inicia sesión.