Quantcast
Viewing all articles
Browse latest Browse all 10

Iteradores en Python

Un iterador es un objeto sobre el que se puede…iterar. Aunque parece una obviedad es así. No puedes iterar sobre un número o tipo entero, ya que carece de la capacidad de iterar. Pero por ejemplo una lista si tiene esa capacidad:

>>> for n in [1,2,3]:
...     print n
... 
1
2
3
>>> 

¿Que hace que un objeto pueda iterar? Lo hace gracias a un “protocolo”. Cuando se itera, en este caso en el bucle ‘for’, se llama a un método denominado ‘__iter__’, este método que pertenece al objeto lista (y a cualquier otro que lo implemente) va a devolver un objeto “iterator” y sobre el es sobre el que vamos a iterar:

>>> dir([])
['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__delslice__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getslice__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__setslice__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
>>> [1,2,3].__iter__()
<listiterator object at 0xb74b69cc>
>>> a = [1,2,3].__iter__()
>>> type(a)
<type 'listiterator'>

Vemos como el objeto lista tiene el método ‘__iter__’ y que al ser llamado devuelve un objeto iterador. Este objeto lo asignamos a ‘a’.

Ahora vemos que el objeto iterador implementa un método llamado ‘next’. Este método proporciona un objeto de la lista cada vez que es llamado o mejor dicho, cada vez que se produce una “iteración”. Al no haber más números en la lista, ‘next’, hace saltar la excepción “StopIteration”. La instrucción ‘for’ no propaga la excepción, simplemente la usa para salir de la iteración o bucle.

>>> dir(a)
['__class__', '__delattr__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__iter__', '__length_hint__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'next']
>>> a.next()
1
>>> a.next()
2
>>> a.next()
3
>>> a.next()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration
>>> 

¿Podríamos construir nosotros nuestro propio iterador?

Como no:

class MyIter(object):
    def __init__(self, n):
        self.lista = range(1, n+1)
        self.index = -1 
        self.limit = n
    def __iter__(self):
        return self
    def next(self):
        self.index += 1
        if self.index == self.limit:
            raise StopIteration
        else:
            return self.lista[self.index]

Implementamos ‘__iter__’ que va a devolver al mismo objeto que implementa ‘next’ un metodo que será llamado hasta que devuelva todos los valores que contiene. En ese momento hace saltar la excepción ‘StopIteration’ para que el consumidor sepa que ya no hay más valores disponibles.

>>> m = myiter.MyIter(8)
>>> for n in m: print n
... 
1
2
3
4
5
6
7
8
>>> 

Relacionado con esto se puede ver el módulo ‘itertools’ y el tema de generadores.


Image may be NSFW.
Clik here to view.
Image may be NSFW.
Clik here to view.

Viewing all articles
Browse latest Browse all 10

Trending Articles