Programación, Literatura y otras artes menores

El esfuerzo de utilizar máquinas para imitar la mente humana siempre me ha parecido bastante tonto: las usaría para imitar algo mejor. –Edsger W. Dijkstra

Pipelines en Python utilizando generators

Posted on | Junio 1, 2009 |

Ya el libro que me estoy leyendo me empieza a develar algunas bondades de python que  este humilde programador de java no conocía: los iterators y generators.

Para un javero como yo los iterators de python son un poco raros, pues en realidad forman parte del lenguaje, o dicho de otra manera, el lenguaje “soporta” el patrón iterator, básicamente nuestra clase iterator debe implementar los métodos next() y __iter__(); el primero es el que manipula el paso como tal, y el segundo devuelve el objeto iterator:

class MyIterator(object):
    def __init__(self,paso):
        self.paso=paso
    def next():
        """Returns the next element."""
        if self.step == 0:
             raise StopIteration
        self.step -= 1
        return self.step
    def __iter__(self):
        """Returns the iterator itself."""
        return self

if __name__ == '__main__':
    for el in MyIterator(4):
        print el

Este ejemplo, y en general todo lo que voy a escribir hoy, está sacado de Expert Python Programming.

Como pueden ver, si están acostumbrados a la interfaz java.util.Iterator de java, esto les debe parecer una bobería… pero, ahora viene lo bueno, los generators.

Los iterators son la base de los generators, yo no voy a hablar extensamente de los generators, pues recién ahora estoy enterándome que existen, pero vale la pena ver como hacer lo que dice el título de este artículo: hacer pipelines.

Resulta que quizás algunos de nosotros(los de java) nos hayamos acostumbrado a ir recorriendo una colección de objetos(antes con un java.util.terator, ahora con un for gracias a los generics), cuando hemos necesitado hacerles operaciones a sus elementos, en python es otra historia, pues además de la función  map(), tenemos los generators

Un generator utiliza la directiva yield para detener la ejecución, a la par que se hace el procesamiento que haya que hacerle al elemento en cuestión,  y queda en espera de una nueva llamada a next(), consideremos lo siguiente:

def power(values):
    for value in values:
        print 'powering %s' % value
        yield value * 2
def adder(values):
    for value in values:
        print 'adding to %s' % value
        if value % 2 ==0:
            yield value + 3
        else:
            yield value +2

Aquí tenemos 2 funciones, una multiplica por dos a todos los elementos de una colección, y la otra, en dependencia si el elemento es par o no, le suma 2 o 3. Lo que haremos ahora será pasarle una lista de numeros a la funcion power(), y su resultado a la función adder():

In [66]: res = adder(power(elms))
In [67]: [res.next() for l in elms]
powering 1
adding to 2
powering 4
adding to 8
powering 7
adding to 14
powering 9
adding to 18
powering 12
adding to 24
powering 19
adding to 38
Out[67]: [5, 11, 17, 21, 27, 41]

En realidad lo que se le pasa a la función adder() es un generator, por lo que al recorrer el resultado mediante next() lo que obtenemos es un generator que apunta a los valores procesados por ambas funciones.

Para que se entienda mejor:

In [73]: g = power(elms)
In [74]: g
Out[74]: generator object power at 0x2d96f50
In [75]: res2 =  adder(g)
In [76]: res2
Out[76]: generator object adder at 0x2da3190
In [77]: [res2.next() for l in elms]
powering 1
adding to 2
powering 4
adding to 8
powering 7
adding to 14
powering 9
adding to 18
powering 12
adding to 24
powering 19
adding to 38
Out[77]: [5, 11, 17, 21, 27, 41]

Anjá, cada función devuelve un objeto generator, que puede ser consumido por otra función y así ad infinitum…

Espero que les sirva de algo, pronto seguiré profundizando en los generators y en su papel en las coroutines.

Comments

Leave a Reply





  • Cuba (40)
    Cultura (1)
    Dimeder (5)
    General (11)
    GNU/Linux (1)
    Internet (10)
    Java (17)
    Literatura (4)
    Mexico (4)
    Programación (64)
    Software (1)
    Software Libre (7)
    Software privativo (2)
    Tecnología (35)

    WP Cumulus Flash tag cloud by Roy Tanck requires Flash Player 9 or better.

  • Meta

  • Archivos