list vs tuple в Python — в чём разница и когда что использовать
Коротко
list — изменяемая (mutable) последовательность. tuple — неизменяемая (immutable) последовательность. Это ключевое отличие, из которого вытекают все остальные: tuple быстрее, занимает меньше памяти и может быть ключом словаря.
Что такое list
list — упорядоченная изменяемая коллекция. Элементы можно добавлять, удалять, менять по индексу. Создаётся через квадратные скобки [] или конструктор list().
# Создание и изменение
fruits = ['яблоко', 'банан', 'вишня']
fruits.append('груша') # ['яблоко', 'банан', 'вишня', 'груша']
fruits[1] = 'апельсин' # ['яблоко', 'апельсин', 'вишня', 'груша']
fruits.remove('вишня') # ['яблоко', 'апельсин', 'груша']
# Сортировка in-place
numbers = [3, 1, 4, 1, 5]
numbers.sort() # [1, 1, 3, 4, 5]
# List comprehension
squares = [x ** 2 for x in range(5)] # [0, 1, 4, 9, 16]list хранит массив указателей на объекты и резервирует дополнительную память для будущих append — это называется overallocation.
Что такое tuple
tuple — упорядоченная неизменяемая коллекция. После создания нельзя добавить, удалить или заменить элементы. Создаётся через круглые скобки () или конструктор tuple().
# Создание
point = (10, 20)
rgb = (255, 128, 0)
singleton = (42,) # запятая обязательна для tuple из одного элемента
# Распаковка
x, y = point # x=10, y=20
# Используется как ключ словаря
grid = {}
grid[(0, 0)] = 'start'
grid[(1, 2)] = 'finish'
# Named tuple для читаемости
from collections import namedtuple
User = namedtuple('User', ['name', 'age', 'city'])
u = User('Анна', 25, 'Москва')
print(u.name) # 'Анна'tuple из одного элемента требует запятую: (42,). Без запятой (42) — это просто число в скобках. Классическая ловушка на собеседовании.
Ключевые отличия
| list | tuple | |
|---|---|---|
| Мутабельность | Изменяемый | Неизменяемый |
| Синтаксис | [1, 2, 3] |
(1, 2, 3) |
| Методы изменения | append, extend, insert, remove, pop, sort | Нет |
| Хешируемость | Нет (нельзя в set/dict key) | Да (если все элементы хешируемы) |
| Память | Больше (overallocation) | Меньше (фиксированный размер) |
| Скорость создания | Медленнее | Быстрее |
| Скорость итерации | Чуть медленнее | Чуть быстрее |
| Типичное использование | Коллекция однородных элементов | Запись с фиксированной структурой |
Когда использовать list
- Коллекция элементов, которая будет расти или уменьшаться
- Результат фильтрации, маппинга, сортировки
- Данные одного типа: список пользователей, список цен
- Стек или очередь (хотя для очереди лучше
deque) - Когда нужно менять элементы по индексу
# Сбор результатов
results = []
for row in data:
if row['status'] == 'active':
results.append(row['id'])
# Сортировка
users = [('Анна', 25), ('Борис', 30), ('Вика', 22)]
users.sort(key=lambda x: x[1]) # по возрастуКогда использовать tuple
- Фиксированная структура: координаты (x, y), RGB (r, g, b)
- Ключ словаря или элемент множества
- Возврат нескольких значений из функции
- Данные, которые не должны случайно измениться
- Аргументы
*argsв функциях (Python передаёт их как tuple)
# Ключ словаря
cache = {}
cache[(user_id, date)] = result
# Возврат нескольких значений
def min_max(values):
return min(values), max(values)
lo, hi = min_max([3, 1, 4, 1, 5]) # lo=1, hi=5
# Константные данные
WEEKDAYS = ('Пн', 'Вт', 'Ср', 'Чт', 'Пт', 'Сб', 'Вс')
HTTP_OK = (200, 201, 204)Типичная ошибка
Думать, что tuple полностью иммутабельный, если внутри есть изменяемые объекты:
# tuple с list внутри — list можно изменить!
t = ([1, 2], [3, 4])
t[0].append(99) # Работает! t = ([1, 2, 99], [3, 4])
t[0] = [5, 6] # TypeError: tuple не позволяет заменить элемент
# Такой tuple нельзя хешировать
hash(t) # TypeError: unhashable type: 'list'Неизменяемость tuple означает, что нельзя заменить ссылки на объекты, но сами объекты (если они mutable) можно менять. Это важно понимать для собеседования.
Вопросы с собеседований
— В чём ключевая разница между list и tuple? — list мутабельный, tuple иммутабельный. Из этого следует: tuple хешируемый (может быть ключом dict), занимает меньше памяти и создаётся быстрее.
— Почему tuple быстрее list? — Tuple имеет фиксированный размер, не нужен overallocation. Python кеширует маленькие tuple (до 20 элементов) для переиспользования. Создание tuple — одна операция, а list требует аллокации с запасом.
— Можно ли изменить элемент tuple? — Нельзя заменить элемент по индексу. Но если элемент сам по себе мутабельный (например, list), его содержимое можно изменить. Это не нарушает иммутабельность tuple — ссылка остаётся прежней.
— Как создать tuple из одного элемента?
— (42,) — с запятой. Без запятой (42) — просто число. Альтернатива: tuple([42]).
— Когда list лучше tuple? — Когда коллекция меняется: добавление, удаление, сортировка. Или когда семантически это набор однородных элементов переменной длины (список заказов, список ID).
FAQ
Насколько tuple экономнее по памяти?
Примерно на 10–20% для небольших коллекций. Для tuple из 5 int — около 80 байт, для list — около 120 байт. Разница в overallocation: list резервирует место для будущих append.
Можно ли конвертировать list в tuple и обратно?
Да: tuple(my_list) и list(my_tuple). Это создаёт новый объект, оригинал не меняется. Конвертация за O(n).
Зачем tuple, если есть namedtuple и dataclass?
namedtuple и dataclass — для случаев, когда нужны именованные поля. Обычный tuple подходит для простых случаев: координаты, возврат из функции, ключ словаря. Если полей больше 3 — лучше namedtuple или dataclass.
Что такое tuple unpacking и зачем он нужен?
Это распаковка: a, b, c = (1, 2, 3). Работает и с list, но чаще используется с tuple. Позволяет вернуть несколько значений из функции и сразу присвоить их переменным. Поддерживает *rest для перехвата оставшихся элементов: first, *rest = (1, 2, 3, 4).