Creando un iterador


In [5]:
class ThingIterator(object):
    def __init__(self, thing):
        self.thing = thing
        self.index = 0
    
    def __iter__(self):
        return self
    
    def next(self):
        if self.index >= len(self.thing.data):
            raise StopIteration
            
        retval = self.thing.data[self.index]
        self.index += 1
        return retval ** 2
    
    # python3 way
    __next__ = next 

class Thing(object):
    def __init__(self, data):
        self.data = data
        
    def __iter__(self):
        return ThingIterator(self)
    
    def iter_squares(self):
        return ThingIterator(self)
        
def iter_squares(x):
    return x.iter_squares()
    
t = Thing([1, 2, 3])
for x in t.iter_squares():
    print(x)


1
4
9

Generadores

Los generadores son funciones que se comportan como iteradores, evitando al programador escribir el código de soporte que hemos visto en la sección anterior. Esto es gracias a la palabra reservada yield que permite al generador emitir un valor sin terminar.


In [24]:
def more():
    yield 20
    yield 300
    yield 4000
    
for x in more():
    print(x)


20
300
4000

In [7]:
def get_squares(seq):
    for x in seq:
        yield x ** 2
        
for x in get_squares([1, 2, 3]):
    print(x)


1
4
9

In [9]:
for x in get_squares(xrange(1, 4)):
    print(x)


1
4
9

In [14]:
gen = get_squares([1, 2, 3])
print(gen)
print(gen.next())
print(gen.next())


<generator object get_squares at 0x7f4db07f54b0>
1
4

generator expressions

Son equivalentes la comprensión de listas para generadores.


In [16]:
gen = (x ** 2 for x in [1, 2, 3])
print(gen)


<generator object <genexpr> at 0x7f4db07f54b0>

In [19]:
sum(x**2 for x in xrange(100) if x % 2)


Out[19]:
166650

itertools

Es un módulo con unas cuantas utilidades interesantes implementadas como iteradores. Aquí vemos algunas:


In [4]:
import itertools as it

In [5]:
x = it.count(5, 3)
print(x.next())
print(x.next())
print(x.next())
print(x.next())


5
8
11
14

In [6]:
x = it.cycle([2, 4, 8])
print(x.next())
print(x.next())
print(x.next())
print(x.next())


2
4
8
2

In [7]:
for x in it.repeat("a", 5):
    print(x)


a
a
a
a
a

In [8]:
for x in it.chain("foo", "bar", "bizz"):
    print(x)


f
o
o
b
a
r
b
i
z
z

imap() e ifilter() son versiones lazy de map() y filter().


In [9]:
for x in it.takewhile(lambda x: x<5, [1,4,6,4,1]):
    print(x)


1
4

In [12]:
for x in it.dropwhile(lambda x: x<5, [1,4,6,4,1]):
    print(x)


6
4
1

In [16]:
print([str.join('', list(x)) for x in it.product('ABCD', repeat=2)])


['AA', 'AB', 'AC', 'AD', 'BA', 'BB', 'BC', 'BD', 'CA', 'CB', 'CC', 'CD', 'DA', 'DB', 'DC', 'DD']

In [17]:
for i,j in it.product(range(5), repeat=2):
    print(i, j)


(0, 0)
(0, 1)
(0, 2)
(0, 3)
(0, 4)
(1, 0)
(1, 1)
(1, 2)
(1, 3)
(1, 4)
(2, 0)
(2, 1)
(2, 2)
(2, 3)
(2, 4)
(3, 0)
(3, 1)
(3, 2)
(3, 3)
(3, 4)
(4, 0)
(4, 1)
(4, 2)
(4, 3)
(4, 4)

In [ ]: