Python Language Espressioni del generatore


Esempio

Le espressioni del generatore sono molto simili alle list comprehensions. La differenza principale è che non crea una serie completa di risultati contemporaneamente; crea un oggetto generatore che può quindi essere iterato sopra.

Ad esempio, vedere la differenza nel seguente codice:

# 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>

Questi sono due oggetti molto diversi:

  • la comprensione della lista restituisce un oggetto list mentre la comprensione del generatore restituisce un generator .

  • generator oggetti del generator non possono essere indicizzati e si avvale della funzione next per ottenere gli oggetti in ordine.

Nota : usiamo xrange poiché crea anche un oggetto generatore. Se usassimo l'intervallo, sarebbe creata una lista. Inoltre, xrange esiste solo nella versione successiva di python 2. In python 3, l' range restituisce solo un generatore. Per ulteriori informazioni, vedere l'esempio delle differenze tra intervallo e xrange .


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 funzione g.next() dovrebbe essere sostituita da next(g) e xrange con range poiché Iterator.next() e xrange() non esistono in Python 3.


Sebbene entrambi possano essere ripetuti in modo simile:

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
"""

Casi d'uso

Le espressioni del generatore vengono valutate pigramente, il che significa che generano e restituiscono ciascun valore solo quando il generatore viene iterato. Ciò è spesso utile durante l'iterazione di set di dati di grandi dimensioni, evitando la necessità di creare un duplicato del set di dati nella memoria:

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

Un altro caso d'uso comune è quello di evitare di iterare su un intero iterabile se ciò non è necessario. In questo esempio, un elemento viene recuperato da un'API remota con ogni iterazione di get_objects() . Migliaia di oggetti possono esistere, devono essere recuperati uno alla volta e abbiamo solo bisogno di sapere se esiste un oggetto che corrisponde a un modello. Usando un'espressione di generatore, quando incontriamo un oggetto che corrisponde al modello.

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