In Python, le stringhe (str) sono oggetti immutabili, il che significa che dopo la creazione non è possibile modificarne il contenuto. Qualsiasi operazione che modifica una stringa (come la concatenazione o la sostituzione di caratteri) crea un nuovo oggetto stringa. Questo garantisce sicurezza e prevedibilità nel lavoro, poiché non è necessario preoccuparsi del fatto che qualcuno modifichi implicitamente una stringa in un'altra parte del codice.
s = 'Hello' s2 = s.replace('H', 'J') # s rimarrà 'Hello', mentre s2 sarà 'Jello'
A differenza delle stringhe, le liste in Python sono oggetti mutabili. Il loro contenuto può essere modificato in loco attraverso l'indicizzazione o metodi, il che a volte porta a effetti indesiderati se la stessa lista viene utilizzata in diverse parti.
Dal punto di vista delle prestazioni: se è necessario modificare frequentemente grandi stringhe (ad esempio, in un ciclo), la meccanica di immutabilità può portare a un'eccessiva allocazione di memoria e a una lento esecuzione del codice. In questi casi, è consigliabile utilizzare una lista per accumulare i frammenti di stringa e quindi unirli tramite ''.join().
Esempio:
# Male (lento per grandi volumi di dati): s = '' for word in words: s += word # In ogni passaggio viene creata una nuova stringa # Bene: parts = [] for word in words: parts.append(word) s = ''.join(parts)
Domanda: Perché il seguente codice "s += 'abc'" è più veloce di "s = s + 'abc'" per le stringhe?
Risposta: Tali domande vengono poste per verificare se una persona comprende che entrambe le operazioni sono in realtà equivalenti per le stringhe (s += 'abc' crea un nuovo oggetto, proprio come s = s + 'abc') — questo è come funziona il comportamento dei tipi in Python. Per le liste, il comportamento è diverso, poiché list += [...] modifica l'oggetto, mentre list = list + [...] crea un nuovo oggetto. Per le stringhe è sempre una nuova stringa.
s = 'hi' s += 'abc' # Nuovo oggetto, la stringa originale non viene cambiata def compare(s): a = s a += 'abc' # id(a) != id(s) <-- oggetti diversi in memoria
Storia
In un progetto dove era richiesta la gestione di grandi log, (analizzando stringhe di diverse centinaia di megabyte), uno sviluppatore ha utilizzato una concatenazione di stringhe naive in un ciclo. Risultato: enormi cali di prestazioni e rapido aumento del consumo di memoria. Dopo l'ottimizzazione tramite lista e join(), il tempo di esecuzione è diminuito di 20 volte.
Storia
In un altro progetto, nel tentativo di "correggere" un carattere in una stringa per indice, il programmatore si aspettava di vedere la modifica della stringa originale. Si è verificato un errore TypeError: 'str' object does not support item assignment. Dopo aver speso diverse ore, il debuggatore ha dovuto creare una nuova stringa utilizzando gli slicing e sostituire il carattere desiderato.
Storia
Quando si passano stringhe a una funzione per "completarle" (ad esempio, aggiungere un suffisso a ogni elemento di una lista), uno degli sviluppatori si aspettava che la stringa cambiasse "in loco". Risultato: la funzione restituiva None (a causa della mancanza di return), e tutte le stringhe rimanevano originali.