Este es una lección introductoria al concepto de Iterables e iteradores en Python.
Hay dos protocolos que es muy probable tenga que utilizar, o posiblemente necesite implementar en algún momento; estos son el protocolo Iterable y el protocolo Iterador. Estos dos protocolos están estrechamente relacionados y son muy utilizados y respaldados por un gran cantidad de tipos.
Una de las razones por las que los iteradores y los iterables son importados es que se pueden usar con sentencias for en Python; esto hace que sea muy fácil integrar un iterable en el código que necesita procesar una secuencia de valores a su vez
El protocolo Iterable es utilizado por tipos donde es posible procesar su contenido. uno a la vez.
Un Iterable es un objeto que proporcionará un Iterador que puede ser utilizado para realizar este procesamiento.
Como tal, el iterable no es el iterador en sí mismo; sino el proveedor del iterador.
Hay muchos tipos iterables en Python, incluidas listas, conjuntos, diccionarios, tuplas, etc. Todos estos son contenedores iterables que proporcionarán un iterador.
Es posible además construir clases que generen iteradores personalizados. De momento trabajaremos con los tipos que ya lo soportan, mencionados arriba.
Un iterador es un objeto que devolverá una secuencia de valores.
Los iteradores pueden ser finitos de longitud o infinito (aunque la mayoría de iteradores orientados a contenedores proporcionan un conjunto fijo de valores.
Un generador es una función especial que se puede utilizar para generar una secuencia de valores que se van a iterar sobre demanda (es decir, cuando se necesitan los valores) en lugar de que producido todo por adelantado.
Lo único que hace que una función generadora trabaje como generador es el uso de palabra clave yield.
def gen_numbers():
yield 1
yield 2
yield 3
Esta es una función generadora, ya que tiene al menos una declaración yield (de hecho, tiene Tres).
Cada vez que se llama a la función gen_numbers () dentro de una instrucción for devolverá uno de los valores asociados con una declaración yield; en este caso el valor 1, luego el valor 2 y finalmente el valor 3 antes de que regrese (termine).
Ahora construimos un ciclo for que va llamando los números a la medida que los necesita. Observe que la variable i en este ejemplos es un iterador entregado por la función gen_numbers().
for i in gen_numbers():
print(i)
1 2 3
Para entender un poco mejor cómo se ejecuta yield discuta en clase el siguiente fragmento (snnipet) de código.
def gen_numbers2():
print('Start')
yield 1
print('Continue')
yield 2
print('Final')
yield 3
print('End')
for i in gen_numbers2():
print(i)
Start 3 Continue 2 Final 3 End
Más adelante veremos clases a plenitud. Aquí introducimos una clase muy sencilla para mostrar como crear un iterable personalizado.
class Evens(object):
def __init__(self, limit):
self.limit = limit
self.val = 0
# Hace esta clase iterable
def __iter__(self):
return self
# Hace esta clase un iterador
def __next__(self):
if self.val > self.limit:
raise StopIteration
else:
return_val = self.val
self.val += 2
return return_val
Solamente vamos a resaltar unas pocas cosas de esta clase Events
El protocolo implica que cuando Python encuentra la definición de la función __iter__() construye la maquinaria para que la clase sea un iterable. De la misma forma, cuando encuentra la función __next__() construye la maquinaria para que la clase entregue un iterador.
Veamos en acción Evens. Discuta en la clase.
print('¡Empezamos')
for i in Evens(16):
print(i,end=', ')
print('\nHecho!')
¡Empezamos 0, 2, 4, 6, 8, 10, 12, 14, 16, Hecho!
¿Qué hace el código anterior línea por línea? Comente el código
Una colección es un contenedor de objetos del mismo tipo. Por defecto en Python existen cuatro tipos de contenedores:
Tuplas (tuple). Esta es una colección de objetos que están ordenados y son inmutables (no pueden modificarse). Las tuplas admiten elementos repetidos y sus miembros son indexados.
Listas (list). Son colecciones de objetos que están ordenado y son mutables, es decir, sus contenidos pueden ser modificados. Los elementos son indexados y permite duplicados.
Conjuntos (set). Son contenedores de datos que no son ordenados ni indexados. Son mutables, pero no admiten duplicados.
Diccionarios (dictionary) Son contenedores no ordenados, que son indexados mediante una clave, la cual referencia a un valor. El valor es retornado cuando se le solicita con la clave. No se admiten claves repetidas, pero si valores repetidos.
Recuerde que todo en Python es realmente un tipo de objeto.