Direct naar de hoofdinhoud
Module 6 · Les 3 van 423/36 in de cursus~10 min
Modulelessen (3/4)

Generator-expressie

Een generatorexpressie is als een lijstbegrip, maar dan met haakjes in plaats van vierkante haakjes. Het verschil is dramatisch: het bouwt geen lijst op in het geheugen, het produceert elementen on-demand, één voor één.

Python
gen = (n * n for n in range(1_000_000))
# istantaneo, memoria costante: nessun calcolo ancora fatto

list_comp = [n * n for n in range(1_000_000)]
# alloca 1M di int in memoria

Luiheid (luie evaluatie)

De generator doet niets totdat iemand om de volgende waarde vraagt:

Python
gen = (n * n for n in range(5))
next(gen)    # 0    (calcolato adesso)
next(gen)    # 1
next(gen)    # 4
# ... e così via, fino a StopIteration

Het raakt uitgeput: na het consumeren van alle elementen is het voor altijd leeg. Om het opnieuw te kunnen gebruiken, moet u het opnieuw maken.

Wanneer moet u het gebruiken?

Wanneer u de resultaten doorgeeft aan een functie die ze in volgorde verbruikt:

Python
total = sum(n * n for n in range(1_000_000))
# nessuna lista intermedia, memoria costante

sum, any, all, max, min, "".join(...) accepteren allemaal generatoren. Als de buitenste functie alleen de aanroephaakjes vereist, is dat mogelijk laat die van de generator weg:

Python
sum((n * n for n in range(10)))    # OK
sum(n * n for n in range(10))      # IDENTICO, più leggibile

any en all: kortsluiting

any(...) en all(...) stoppen met herhalen zodra ze het antwoord hebben. Met een generator worden de volgende elementen niet eens berekend.

Python
nums = [1, 2, 3, 4, 5]
any(n > 3 for n in nums)    # True (si ferma a 4)
all(n > 0 for n in nums)    # True
all(n > 2 for n in nums)    # False (si ferma a 1)

Patroon: luie pijplijn

Python
righe = (linea.strip() for linea in testo.splitlines())
non_vuote = (r for r in righe if r)
prime_dieci = []
for r in non_vuote:
    prime_dieci.append(r)
    if len(prime_dieci) == 10:
        break

Geen tussenlijst, zelfs niet bij grote inputs.

Generatoren verbruiken met som, alles, alles

Generatorexpressies zijn perfect om rechtstreeks door te geven aan functies die iterabelen gebruiken, zoals sum(), any() of all(). In dit geval kunt u de buitenste haakjes van de generatoruitdrukking weglaten door simpelweg te schrijven:

Python
squares_sum = sum(x**2 for x in range(10))

Hierdoor blijft uw code schoon en zeer geheugenefficiënt.

Probeer het

Oefening#python.m6.l3.e1
Pogingen: 0Laden…

Bereken de som van de kwadraten van de getallen van 1 tot en met 100 met behulp van een generatorexpressie binnen sum(). Wijs het toe aan 'tot'. Evalueer 'tot'.

Editor laden…
Toon hint

bereik(1, 101) omvat 100.

Oplossing beschikbaar na 3 pogingen

Oefening beoordelen

Oefening#python.m6.l3.e2
Pogingen: 0Laden…

Gegeven `words = ['ciao', 'mondo', 'PYTHON', 'java']`, gebruik any() met een generatorexpressie om te controleren of MINSTENS één woord hoofdletters is (.isupper()). Wijs het resultaat toe aan `has_uppercase`. Evalueer `heeft_hoofdletter`.

Editor laden…
Toon hint

any(p.isupper() voor p in woorden)

Oplossing beschikbaar na 3 pogingen

Extra uitdaging

Oefening#python.m6.l3.e3
Pogingen: 0Laden…

Use a generator expression passed directly to the `sum()` function to calculate the sum of the squares of all integers from 1 to 100 inclusive. Store the result in `total_sum` and evaluate it.

Editor laden…
Toon hint

Schrijf totaal_som = som(x**2 voor x binnen bereik(1, 101)). Dubbele haakjes zijn niet nodig.

Oplossing beschikbaar na 3 pogingen