ProgrammazioneData Engineer

Spiega come funziona la valutazione pigra in Python e dove viene applicata oltre ai generatori. Quali sono i vantaggi dei calcoli pigri?

Supera i colloqui con l'assistente IA Hintsage

Risposta.

La valutazione pigra (lazy evaluation) è un concetto chiave della programmazione efficiente, in cui i valori vengono calcolati solo quando necessario. Storicamente in Python, tutte le strutture incorporate principali (liste, tuple) erano "drogate": creavano e memorizzavano in anticipo tutti gli elementi. Con l'aumento dei volumi di dati e delle operazioni di elaborazione dei flussi, è emersa la necessità di calcoli pigri.

Problema: i calcoli drogati portano a un utilizzo inefficiente della memoria e del tempo in situazioni in cui è possibile ottenere risultati gradualmente, come nel filtraggio, nella trasformazione di lunghe collezioni o nello streaming di file.

Soluzione: in Python sono stati introdotti molti strumenti per calcoli pigri: generatori, iteratori, così come le funzioni della libreria standard (map, filter, zip, enumerate) e il modulo itertools. Tutti essi restituiscono non collezioni pronte, ma oggetti "pigri" che forniscono il risultato uno alla volta.

Esempio di codice:

result = map(lambda x: x * x, range(100)) # restituirà un generatore-iteratore for y in result: print(y) # i valori vengono calcolati iterando import itertools inf = itertools.count(1) for i in inf: if i > 3: break print(i) # 1, 2, 3

Caratteristiche principali:

  • Non tutti gli elementi sono memorizzati in memoria: vengono calcolati "su richiesta".
  • Può lavorare con flussi di dati infiniti.
  • Consente di elaborare collezioni che fisicamente non esistono del tutto (ad esempio, un flusso di dati dalla rete).

Domande insidiose.

Le funzioni map/filter restituiscono sempre una lista in Python3?

No, in Python 3 queste funzioni restituiscono iteratori, non liste. Per ottenere una lista è necessario racchiudere il risultato in list().

x = map(int, ['1', '2']) # <oggetto mappa> list(x) # [1, 2]

È possibile ottenere la lunghezza del risultato di map senza convertirlo in una lista?

No, un iteratore non sa in anticipo quanti elementi contiene finché non passa attraverso tutti. È necessario calcolarlo tramite list(), il che annulla la pigrezza.

La funzione range in Python3 è drogata o pigra?

Pigramente: range crea un "oggetto range" — calcola gli elementi su richiesta, senza memorizzare tutta la sequenza.

Errori comuni e anti-pattern

  • Trasformano implicitamente oggetti pigri in liste, perdendo il vantaggio del risparmio di memoria.
  • Considerano iteratori e generatori intercambiabili con le liste (ma non possono essere indicizzati o ripetuti).
  • Applicano len() agli oggetti pigri e ottengono errori.

Esempio dalla vita reale

Caso negativo

Uno script elabora un enorme file CSV, creando una lista di tutte le righe tramite list(open(f)). Il server "muore" a causa della mancanza di memoria con un file di grandi dimensioni.

Vantaggi:

  • Indicizzazione veloce per una riga specifica.

Svantaggi:

  • Alto consumo di memoria.
  • Il programma non scala a grandi dati.

Caso positivo

Il codice utilizza la valutazione pigra: scorre le righe del file con un iteratore for line in open(f), oppure le elabora tramite map/filter senza creare collezioni intermedie.

Vantaggi:

  • Lavoro con file di qualsiasi dimensione.
  • Minima memoria.

Svantaggi:

  • Se è necessario l'accesso casuale per indice, sarà necessaria una struttura dati separata.