Temas relacionados con los generadores en Python

Beginner

This tutorial is from open-source community. Access the source code

Introducción

Esta sección presenta algunos temas adicionales relacionados con los generadores, incluyendo expresiones generadoras y el módulo itertools.

Expresiones Generadoras

Una versión generadora de una comprensión de lista.

>>> a = [1,2,3,4]
>>> b = (2*x for x in a)
>>> b
<generator object at 0x58760>
>>> for i in b:
...   print(i, end=' ')
...
2 4 6 8
>>>

Diferencias con las Comprensiones de Lista.

  • No construye una lista.
  • El único propósito útil es la iteración.
  • Una vez consumido, no se puede reutilizar.

Sintaxis general.

(<expression> for i in s if <conditional>)

También puede servir como argumento de función.

sum(x*x for x in a)

Se puede aplicar a cualquier iterable.

>>> a = [1,2,3,4]
>>> b = (x*x for x in a)
>>> c = (-x for x in b)
>>> for i in c:
...   print(i, end=' ')
...
-1 -4 -9 -16
>>>

El principal uso de las expresiones generadoras es en código que realiza algún cálculo sobre una secuencia, pero solo utiliza el resultado una vez. Por ejemplo, eliminar todos los comentarios de un archivo.

f = open('somefile.txt')
lines = (line for line in f if not line.startswith('#'))
for line in lines:
  ...
f.close()

Con los generadores, el código se ejecuta más rápido y utiliza poco memoria. Es como un filtro aplicado a un flujo.

¿Por qué Generadores?

  • Muchos problemas se expresan con mucha más claridad en términos de iteración.
    • Bucle sobre una colección de elementos y realizar algún tipo de operación (buscar, reemplazar, modificar, etc.).
    • Las tuberías de procesamiento se pueden aplicar a una amplia variedad de problemas de procesamiento de datos.
  • Mejora en la eficiencia de memoria.
    • Solo producen valores cuando se necesitan.
    • En contraste con la construcción de listas enormes.
    • Pueden operar sobre datos en streaming
  • Los generadores fomentan la reutilización de código
    • Separa la iteración del código que utiliza la iteración
    • Puedes construir una caja de herramientas de funciones de iteración interesantes y mezclarlas y combinarlas.

Módulo itertools

El itertools es un módulo de la biblioteca con varias funciones diseñadas para ayudar con iteradores/generadores.

itertools.chain(s1,s2)
itertools.count(n)
itertools.cycle(s)
itertools.dropwhile(predicate, s)
itertools.groupby(s)
itertools.ifilter(predicate, s)
itertools.imap(function, s1,... sN)
itertools.repeat(s, n)
itertools.tee(s, ncopies)
itertools.izip(s1,..., sN)

Todas las funciones procesan los datos de forma iterativa. Implementan varios tipos de patrones de iteración.

Más información en el tutorial Generator Tricks for Systems Programmers de PyCon '08.

En los ejercicios anteriores, escribió un código que seguía las líneas que se escribían en un archivo de registro y las analizaba en una secuencia de filas. Este ejercicio continúa construyendo sobre eso. Asegúrese de que stocksim.py siga en ejecución.

Ejercicio 6.13: Expresiones Generadoras

Las expresiones generadoras son una versión generadora de una comprensión de lista. Por ejemplo:

>>> nums = [1, 2, 3, 4, 5]
>>> squares = (x*x for x in nums)
>>> squares
<generator object <genexpr> at 0x109207e60>
>>> for n in squares:
...     print(n)
...
1
4
9
16
25

A diferencia de una comprensión de lista, una expresión generadora solo se puede usar una vez. Por lo tanto, si intenta otro bucle for, no obtiene nada:

>>> for n in squares:
...     print(n)
...
>>>

Ejercicio 6.14: Expresiones Generadoras en Argumentos de Función

A veces, las expresiones generadoras se colocan en los argumentos de funciones. Al principio puede parecer un poco extraño, pero intente este experimento:

>>> nums = [1,2,3,4,5]
>>> sum([x*x for x in nums])    ## Una comprensión de lista
55
>>> sum(x*x for x in nums)      ## Una expresión generadora
55
>>>

En el ejemplo anterior, la segunda versión que utiliza generadores utilizaría significativamente menos memoria si se estuviera manipulando una lista grande.

En su archivo portfolio.py, realizó algunos cálculos que implicaban comprensiones de lista. Intente reemplazarlas con expresiones generadoras.

Ejercicio 6.15: Simplificación del código

Las expresiones generadoras a menudo son un reemplazo útil de pequeñas funciones generadoras. Por ejemplo, en lugar de escribir una función como esta:

def filter_symbols(rows, names):
    for row in rows:
        if row['name'] in names:
            yield row

Podría escribir algo como esto:

rows = (row for row in rows if row['name'] in names)

Modifique el programa ticker.py para usar expresiones generadoras en la medida de lo posible.

Resumen

¡Felicitaciones! Has completado el laboratorio de Generadores Avanzados. Puedes practicar más laboratorios en LabEx para mejorar tus habilidades.