В Python списки (list) — изменяемые структуры, а кортежи (tuple) — неизменяемые.
Пример, иллюстрирующий изменение list и tuple:
lst = [1, 2, 3] lst.append(4) # OK lst[1] = 20 # OK tup = (1, 2, 3) tup[1] = 20 # TypeError
Производительность:
Вопрос: Почему операции добавления элементов к списку обычно выполняются быстро (O(1)), если с точки зрения массива это должно приводить к перераспределению памяти?
Ответ:
Python реализует динамические массивы с "выделением лишней памяти" сразу для нескольких элементов. Поэтому append обычно занимает O(1), а перераспределение памяти происходит только при реальном исчерпании резервного блока.
Пример:
import sys lst = [] for i in range(10): lst.append(i) print(len(lst), sys.getsizeof(lst)) # Размер памяти растёт не строго линейно
История
В одном проекте для ключей словаря использовали list. Разработчик не знал, что списки не хэшируются (mutability), что вызвало ошибку "TypeError: unhashable type: 'list'".
Разработчик часто создавал длинные списки, конкатенируя их через +. Это приводило к дополнительным копированиям массива и высоким накладным расходам по памяти и времени. Эффективнее было использовать append в цикле или генераторы.
В системе логирования для хранения временных меток выбрали кортежи, думая, что за счёт immutable будет быстрее. Но периодически возникала необходимость в модификации, что требовало постоянно создавать новые кортежи (copy-on-write) и приводило к замедлению работы по сравнению с использованием списков.