ProgrammazioneSviluppatore Python

Spiega i principi di funzionamento dei gestori di memoria nelle liste e tuple di Python. Qual è la differenza tra la modifica/aggiunta di elementi in list e tuple e come influisce sulle prestazioni?

Supera i colloqui con l'assistente IA Hintsage

Risposta

In Python, le liste (list) sono strutture mutabili, mentre le tuple (tuple) sono immutabili.

  • list: Quando vengono aggiunti nuovi elementi (append, extend, insert), Python alloca "con margine" blocchi di memoria per minimizzare il numero di allocazioni durante la crescita dell'array ("strategia di sovrallocazione"). La rimozione di elementi (pop, remove) avviene rapidamente, ma a volte può causare la riallocazione della memoria.
  • tuple: La dimensione della tupla è fissa, gli elementi non possono essere modificati o aggiunti, il che garantisce un'alta velocità delle operazioni di lettura e un minore consumo di memoria rispetto alle liste quando si memorizzano grandi quantità di dati immutabili.

Esempio che illustra la modifica di list e tuple:

lst = [1, 2, 3] lst.append(4) # OK lst[1] = 20 # OK tup = (1, 2, 3) tup[1] = 20 # TypeError

Prestazioni:

  • Le liste sono ottime per le collezioni che cambiano frequentemente.
  • Le tuple sono leggermente più veloci, più ottimali in termini di memoria (grazie alla dimensione fissa e ai principi di hashing), adatte per chiavi dei dizionari, valori restituiti dalle funzioni (dati immutabili).

Domanda trabocchetto

Domanda: Perché le operazioni di aggiunta di elementi a una lista vengono generalmente eseguite rapidamente (O(1)), se dal punto di vista dell'array dovrebbero portare a una riallocazione della memoria?

Risposta:

Python implementa array dinamici con "allocazione di memoria in eccesso" subito per più elementi. Pertanto, append di solito richiede O(1) e la riallocazione della memoria avviene solo al reale esaurimento del blocco di riserva.

Esempio:

import sys lst = [] for i in range(10): lst.append(i) print(len(lst), sys.getsizeof(lst)) # La dimensione della memoria cresce non in modo rigorosamente lineare

Storia

Esempio 1

In un progetto, per le chiavi del dizionario sono state utilizzate list. Lo sviluppatore non sapeva che le liste non sono hashabili (mutabilità), il che ha causato l'errore "TypeError: tipo non hashabile: 'list'".


Esempio 2

Lo sviluppatore creava spesso lunghe liste concatenandole tramite +. Questo portava a ulteriori copie dell'array e a costi elevati in termini di memoria e tempo. Era più efficiente utilizzare append in un ciclo o generatori.


Esempio 3

Nel sistema di logging, per memorizzare i timestamp sono state scelte tuple, pensando che grazie a immutabilità sarebbe stato più veloce. Ma periodicamente si presenta la necessità di modifiche, il che richiedeva di creare continuamente nuove tuple (copy-on-write) e portava a un rallentamento rispetto all'uso di liste.