Python Language Expresiones del generador


Ejemplo

Las expresiones generadoras son muy similares a las listas de comprensión. La principal diferencia es que no crea un conjunto completo de resultados a la vez; crea un objeto generador que luego puede ser iterado.

Por ejemplo, vea la diferencia en el siguiente código:

# list comprehension
[x**2 for x in range(10)]
# Output: [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
Python 2.x 2.4
# generator comprehension
(x**2 for x in xrange(10))
# Output: <generator object <genexpr> at 0x11b4b7c80>

Estos son dos objetos muy diferentes:

  • la lista de comprensión devuelve un objeto de list mientras que la comprensión del generador devuelve un generator .

  • generator objetos generator no se pueden indexar y hace uso de la next función para ordenar los artículos.

Nota : Utilizamos xrange ya que también crea un objeto generador. Si usaríamos el rango, se crearía una lista. Además, xrange solo existe en la versión posterior de python 2. En python 3, range solo devuelve un generador. Para obtener más información, consulte el ejemplo de Diferencias entre las funciones de rango y rango .


Python 2.x 2.4
g = (x**2 for x in xrange(10))
print(g[0])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'generator' object has no attribute '__getitem__'

g.next()  # 0
g.next()  # 1
g.next()  # 4
...
g.next()  # 81

g.next()  # Throws StopIteration Exception
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration
Python 3.x 3.0

NOTA: La función g.next() debe sustituirse por next(g) y xrange con range ya que Iterator.next() y xrange() no existen en Python 3.


Aunque ambos pueden ser iterados de manera similar:

for i in [x**2 for x in range(10)]:
    print(i)

"""
Out:
0
1
4
...
81
"""
Python 2.x 2.4
for i in (x**2 for x in xrange(10)):
    print(i)

"""
Out:
0
1
4
.
.
.
81
"""

Casos de uso

Las expresiones del generador se evalúan perezosamente, lo que significa que generan y devuelven cada valor solo cuando el generador está iterado. Esto suele ser útil cuando se itera a través de grandes conjuntos de datos, evitando la necesidad de crear un duplicado del conjunto de datos en la memoria:

for square in (x**2 for x in range(1000000)):
    #do something

Otro caso de uso común es evitar la iteración en todo un iterable si no es necesario hacerlo. En este ejemplo, un elemento se recupera de una API remota con cada iteración de get_objects() . Pueden existir miles de objetos, deben recuperarse uno por uno, y solo necesitamos saber si existe un objeto que coincida con un patrón. Al usar una expresión generadora, cuando encontramos un objeto que coincide con el patrón.

def get_objects():
    """Gets objects from an API one by one"""
    while True:
        yield get_next_item()

def object_matches_pattern(obj):
    # perform potentially complex calculation
    return matches_pattern

def right_item_exists():
    items = (object_matched_pattern(each) for each in get_objects())
    for item in items:
        if item.is_the_right_one:


            return True
    return False