W Pythonie listy (list) są strukturami mutowalnymi, a krotki (tuple) są niemutowalne.
Przykład ilustrujący zmianę listy i krotki:
lst = [1, 2, 3] lst.append(4) # OK lst[1] = 20 # OK tup = (1, 2, 3) tup[1] = 20 # TypeError
Wydajność:
Pytanie: Dlaczego operacje dodawania elementów do listy zazwyczaj są wykonywane szybko (O(1)), skoro z punktu widzenia tablicy powinny prowadzić do przemieszczenia pamięci?
Odpowiedź:
Python implementuje dynamiczne tablice dengan "przydzieleniem nadmiarowej pamięci" od razu dla kilku elementów. Dlatego append zazwyczaj zajmuje O(1), a przemieszczenie pamięci zachodzi tylko wtedy, gdy faktycznie wyczerpano rezerwowy blok.
Przykład:
import sys lst = [] for i in range(10): lst.append(i) print(len(lst), sys.getsizeof(lst)) # Rozmiar pamięci rośnie nie ściśle liniowo
Historia
W jednym projekcie do kluczy słownika używano list. Programista nie wiedział, że listy nie są haszowane (mutowalność), co spowodowało błąd "TypeError: unhashable type: 'list'".
Programista często tworzył długie listy, łącząc je poprzez +. Prowadziło to do dodatkowych kopiowań tablicy i wysokich kosztów pamięci i czasu. Efektywniej było używać append w pętli lub generatorów.
W systemie logowania do przechowywania znaczników czasu wybrano krotki, myśląc, że dzięki immutability będzie szybciej. Jednak czasami zachodziła potrzeba modyfikacji, co wymagało ciągłego tworzenia nowych krotek (copy-on-write) i prowadziło do spowolnienia w porównaniu do używania list.