Iteradores de Python
Iteradores de Python
Los iteradores son objetos sobre los que se puede iterar. En este tutorial, aprenderá cómo funciona el iterador y cómo puede crear su propio iterador utilizando los métodos __iter__ y __next__.
Video:iteradores de Python
Iteradores en Python
Los iteradores están en todas partes en Python. Están elegantemente implementados dentro de for
bucles, comprensiones, generadores, etc. pero están ocultos a simple vista.
Iterator en Python es simplemente un objeto que se puede iterar. Un objeto que devolverá datos, un elemento a la vez.
Técnicamente hablando, un objeto iterador de Python debe implementar dos métodos especiales, __iter__()
y __next__()
, denominados colectivamente protocolo iterador .
Un objeto se llama iterable si podemos obtener un iterador de él. La mayoría de los contenedores incorporados en Python como:lista, tupla, cadena, etc. son iterables.
El iter()
función (que a su vez llama al __iter__()
método) devuelve un iterador de ellos.
Iterando a través de un iterador
Usamos el next()
función para iterar manualmente a través de todos los elementos de un iterador. Cuando lleguemos al final y no haya más datos para devolver, aumentará el StopIteration
Excepción. El siguiente es un ejemplo.
# define a list
my_list = [4, 7, 0, 3]
# get an iterator using iter()
my_iter = iter(my_list)
# iterate through it using next()
# Output: 4
print(next(my_iter))
# Output: 7
print(next(my_iter))
# next(obj) is same as obj.__next__()
# Output: 0
print(my_iter.__next__())
# Output: 3
print(my_iter.__next__())
# This will raise error, no items left
next(my_iter)
Salida
4 7 0 3 Traceback (most recent call last): File "<string>", line 24, in <module> next(my_iter) StopIteration
Una forma más elegante de iterar automáticamente es usando el bucle for. Con esto, podemos iterar sobre cualquier objeto que pueda devolver un iterador, por ejemplo, una lista, una cadena, un archivo, etc.
>>> for element in my_list:
... print(element)
...
4
7
0
3
Funcionamiento del bucle for para iteradores
Como vemos en el ejemplo anterior, el for
loop pudo iterar automáticamente a través de la lista.
De hecho, el for
loop puede iterar sobre cualquier iterable. Echemos un vistazo más de cerca a cómo el for
loop está realmente implementado en Python.
for element in iterable:
# do something with element
En realidad se implementa como.
# create an iterator object from that iterable
iter_obj = iter(iterable)
# infinite loop
while True:
try:
# get the next item
element = next(iter_obj)
# do something with element
except StopIteration:
# if StopIteration is raised, break from loop
break
Entonces, internamente, el for
loop crea un objeto iterador, iter_obj
llamando al iter()
en el iterable.
Irónicamente, este for
loop es en realidad un ciclo while infinito.
Dentro del ciclo, llama a next()
para obtener el siguiente elemento y ejecuta el cuerpo del for
bucle con este valor. Después de que se agoten todos los elementos, StopIteration
se eleva, que se atrapa internamente y el bucle termina. Tenga en cuenta que cualquier otro tipo de excepción pasará.
Creación de iteradores personalizados
Construir un iterador desde cero es fácil en Python. Solo tenemos que implementar el __iter__()
y el __next__()
métodos.
El __iter__()
El método devuelve el propio objeto iterador. Si es necesario, se puede realizar alguna inicialización.
El __next__()
El método debe devolver el siguiente elemento de la secuencia. Al llegar al final, y en llamadas posteriores, debe subir StopIteration
.
Aquí mostramos un ejemplo que nos dará la siguiente potencia de 2 en cada iteración. El exponente de potencia comienza desde cero hasta un número establecido por el usuario.
Si no tiene idea sobre la programación orientada a objetos, visite Programación orientada a objetos de Python.
class PowTwo:
"""Class to implement an iterator
of powers of two"""
def __init__(self, max=0):
self.max = max
def __iter__(self):
self.n = 0
return self
def __next__(self):
if self.n <= self.max:
result = 2 ** self.n
self.n += 1
return result
else:
raise StopIteration
# create an object
numbers = PowTwo(3)
# create an iterable from the object
i = iter(numbers)
# Using next to get to the next iterator element
print(next(i))
print(next(i))
print(next(i))
print(next(i))
print(next(i))
Salida
1 2 4 8 Traceback (most recent call last): File "/home/bsoyuj/Desktop/Untitled-1.py", line 32, in <module> print(next(i)) File "<string>", line 18, in __next__ raise StopIteration StopIteration
También podemos usar un for
bucle para iterar sobre nuestra clase de iterador.
>>> for i in PowTwo(5):
... print(i)
...
1
2
4
8
16
32
Iteradores infinitos de Python
No es necesario que el elemento en un objeto iterador tenga que estar agotado. Puede haber infinitos iteradores (que nunca terminan). Debemos tener cuidado al manejar dichos iteradores.
Aquí hay un ejemplo simple para demostrar infinitos iteradores.
La función integrada iter()
se puede llamar con dos argumentos donde el primer argumento debe ser un objeto invocable (función) y el segundo es el centinela. El iterador llama a esta función hasta que el valor devuelto es igual al centinela.
>>> int()
0
>>> inf = iter(int,1)
>>> next(inf)
0
>>> next(inf)
0
Podemos ver que el int()
la función siempre devuelve 0. Así que pasándola como iter(int,1)
devolverá un iterador que llama a int()
hasta que el valor devuelto sea igual a 1. Esto nunca sucede y obtenemos un iterador infinito.
También podemos construir nuestros propios iteradores infinitos. El siguiente iterador, en teoría, devolverá todos los números impares.
class InfIter:
"""Infinite iterator to return all
odd numbers"""
def __iter__(self):
self.num = 1
return self
def __next__(self):
num = self.num
self.num += 2
return num
Una ejecución de muestra sería la siguiente.
>>> a = iter(InfIter())
>>> next(a)
1
>>> next(a)
3
>>> next(a)
5
>>> next(a)
7
Y así sucesivamente...
Tenga cuidado de incluir una condición de terminación al iterar sobre este tipo de iteradores infinitos.
La ventaja de usar iteradores es que ahorran recursos. Como se muestra arriba, podríamos obtener todos los números impares sin almacenar todo el sistema numérico en la memoria. Podemos tener infinitos elementos (teóricamente) en una memoria finita.
Hay una manera más fácil de crear iteradores en Python. Para obtener más información, visite:Generadores de Python con rendimiento.
python