Iteradores

Python SELF ES
Nivel 19 , Lección 4
Disponible

5.1 Iterable y Iterator

Como ya sabes, los iteradores son objetos que implementan el protocolo de iterador, permitiendo obtener elementos de una colección uno a uno. Los iteradores se utilizan ampliamente en Python para recorrer los elementos de secuencias como listas, tuplas y cadenas de texto.

Veamos cómo están estructurados los iteradores y cómo utilizarlos.

Objeto iterativo (Iterable)

Para que un objeto pueda recorrerse con un bucle for, debe ser iterable – Iterable. Esto significa que nuestro objeto debe implementar el método __iter__(), que devuelve un objeto iterador.

Objeto iterador (Iterator)

Este es un objeto especial que tiene la función __next__() para devolver el siguiente elemento de la secuencia. Cuando los elementos se acaban, el método __next__() lanza una excepción StopIteration como señal de que la iteración ha finalizado.

El iterador también debe implementar el método __iter__(), que devuelve el propio iterador.

Ejemplo usando funciones integradas de Python

En este ejemplo, la lista numbers es un objeto iterable. Obtenemos un iterador usando la función iter() y usamos la función next() para recorrer los elementos hasta que se lance la excepción StopIteration.


# Objeto iterable
numbers = [1, 2, 3, 4, 5]
            
# Obtenemos un iterador del objeto iterable
iterator = iter(numbers)
            
# Usamos el iterador para recorrer los elementos
try:
    while True:
        number = next(iterator)
        print(number)
except StopIteration:
    pass
        

Es precisamente lo que sucede cuando escribes un código del tipo:


# Objeto iterable
numbers = [1, 2, 3, 4, 5]
            
for number in numbers:
    print(number)
        

5.2 La esencia del iterador

Un iterador es un objeto que nos ayuda a recorrer un grupo de elementos uno a uno. Sus implementaciones pueden ser diversas. Vamos a escribir nuestra propia clase, en la que implementamos todos los requisitos que se exigen a un iterador.

Paso 1. Para comenzar, crearemos nuestra propia clase

Que devuelva secuencialmente números de start a end


class MyIterator:
    def __init__(self, start, end):
        self.current = start
        self.end = end
        

Paso 2. Soporte para la función __iter__

Ahora necesitamos añadirle la función __iter__, que devolverá un objeto iterador, en el que se llamará la función __next()__. Vamos a devolver una referencia a nuestro propio objeto – esto no está prohibido.


class MyIterator:
    def __init__(self, start, end):
        self.current = start
        self.end = end
        
    def __iter__(self):
        return self
        

Paso 3. Soporte para la función __next__

Ahora necesitamos añadir a nuestro objeto iterador la función __next__, que devolverá el siguiente elemento de nuestra lista. Simplemente usaremos la variable current:


def __next__(self):
    current = self.current
    self.current += 1
    return current
        

Paso 4. Detener el iterador

Si el iterador ya ha devuelto todos los valores que planeaba, debe lanzar una excepción StopIteration. Vamos a ajustar un poco nuestra última función:


def __next__(self):
    if self.current >= self.end:
        raise StopIteration
    current = self.current
    self.current += 1
    return current
        

Genial. Ahora podemos usar nuestro iterador. Aquí tienes un ejemplo de todo nuestro código:


class MyIterator:
    def __init__(self, start, end):
        self.current = start
        self.end = end
        
    def __iter__(self):
        return self
        
    def __next__(self):
        if self.current >= self.end:
            raise StopIteration
        current = self.current
        self.current += 1
        return current
        
# Creamos una instancia del iterador personalizado
my_iter = MyIterator(1, 5)
        
# Usamos el iterador para recorrer los elementos
for num in my_iter:
    print(num)

5.3 Un iterador correcto

¿Qué tiene de malo el iterador del ejemplo anterior? Sí, es un iterador, funciona, pero es demasiado primitivo. Con él no es posible recorrer la misma colección de elementos simultáneamente con diferentes iteradores.

Sería más adecuado escribir un código que no devolviera una referencia a sí mismo en el método __iter__, sino un objeto separado, que ya devuelva correctamente todos los elementos.

Ejemplo:


class MyIterable:
    def __init__(self, data):
        self.data = data
    
    def __iter__(self):
        return MyIterator(self.data)
    
class MyIterator:
    def __init__(self, data):
        self.data = data
        self.index = 0
    
    def __iter__(self):
        return self
    
    def __next__(self):
        if self.index >= len(self.data):
            raise StopIteration
        item = self.data[self.index]
        self.index += 1
        return item
    
# Uso
my_iterable = MyIterable([1, 2, 3, 4])
for item in my_iterable:
    print(item)
    

En este ejemplo tenemos dos clases — a la primera se le pasa la colección, por la que vamos a recorrer con un iterador. Y la segunda es el iterador en sí, que devuelve los elementos de la colección en el método next(). También es bastante simple, pero así es como debes añadir iteradores a tus clases.

1
Опрос
Módulos y paquetes,  19 уровень,  4 лекция
недоступен
Módulos y paquetes
Módulos y paquetes
Comentarios
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION