Изменяемые (mutable) типы данных в Python можно менять после создания — это списки (list), словари (dict), множества (set) и bytearray. Неизменяемые (immutable) менять нельзя: числа (int, float, bool), строки (str), кортежи (tuple), frozenset и bytes. Любая «модификация» неизменяемого объекта на деле создаёт новый объект с новым идентификатором.
Понимание этого различия — базовый навык: от него зависит поведение структур данных, аргументов функций и производительность программы. Ниже — определения, таблица типов, проверка через id() и is, а также типичные ловушки, на которых спотыкаются даже опытные разработчики.
Что такое изменяемые и неизменяемые типы данных в Python
Python — язык с динамической типизацией, и все данные в нём являются объектами. Каждый объект имеет три характеристики: идентичность (адрес в памяти), тип и значение. По официальной документации Python, идентичность и тип объекта не меняются никогда, а вот значение — может, и именно это делит типы на две категории.
Неизменяемые типы (immutable)
Значение такого объекта нельзя изменить после создания. Любая операция, которая «меняет» его, возвращает новый объект. Это защищает данные от случайных модификаций и делает объекты хешируемыми. К неизменяемым относятся:
- Целые числа —
int - Вещественные и комплексные числа —
float,complex - Логический тип —
bool - Строки —
str - Кортежи —
tuple - Байтовые строки —
bytes - Неизменяемые множества —
frozenset
Изменяемые типы (mutable)
Их содержимое можно менять на месте, без создания нового объекта. Это экономит память для больших структур, но требует аккуратности: изменение через одну ссылку видно всем ссылкам на тот же объект. К изменяемым относятся:
- Списки —
list - Словари —
dict - Множества —
set - Изменяемые байтовые массивы —
bytearray
- Выполним базовые задачи на российских нейросетях и посмотрим на результаты!
- Файл-инструкцию «Как сделать нейро-фотосессию из своего фото бесплатно, без иностранных карт и прочих сложностей»
- Покажем 10+ способов улучшить свою жизнь с ИИ каждому — от ребенка и пенсионера до управленца и предпринимателя
- Возможность получить Доступ в Нейроклуб на целый месяц
- Как ИИ ускоряет работу и приносит деньги
- За 2 часа вы получите четкий план, как начать работать с ИИ прямо сейчас!

- ПОКАЖЕМ, КАК РАЗВЕРНУТЬ МОДЕЛЬ нейросети DEEPSEEK R1 ПРЯМО НА СВОЁМ КОМПЬЮТЕРЕ
- Где и как применять? Потестируем модель после установки на разных задачах
- Как дообучить модель под себя?
Таблица изменяемых и неизменяемых типов данных Python
| Тип | Категория | Хешируемый | Можно ли ключом словаря |
|---|---|---|---|
| int, float, complex, bool | Неизменяемый | Да | Да |
| str | Неизменяемый | Да | Да |
| tuple | Неизменяемый* | Да* | Да* |
| bytes | Неизменяемый | Да | Да |
| frozenset | Неизменяемый | Да | Да |
| list | Изменяемый | Нет | Нет |
| dict | Изменяемый | Нет | Нет |
| set | Изменяемый | Нет | Нет |
| bytearray | Изменяемый | Нет | Нет |
* Кортеж хешируем и годится в ключи, только если все его элементы неизменяемы. Кортеж со списком внутри — нет.
Как проверить изменяемость: функции id() и is

Функция id() возвращает идентификатор объекта — в CPython это адрес в памяти. Оператор is сравнивает именно идентичность, а не значения. Сравните поведение неизменяемого и изменяемого типа:
Пример с неизменяемым типом
x = 10
print(id(x)) # некоторый адрес, например 140712...
x += 1
print(id(x)) # ДРУГОЙ адрес — создан новый объект
Число не поменялось «внутри»: x += 1 создало новый объект 11 и привязало к нему имя x. Прежняя десятка осталась неизменной.
Пример с изменяемым типом
nums = [1, 2, 3]
print(id(nums)) # некоторый адрес
nums.append(4)
print(id(nums)) # ТОТ ЖE адрес — объект изменён на месте
Список модифицируется на месте, идентификатор сохраняется. Отсюда — разница между == и is:
a = [1, 2]
b = [1, 2]
print(a == b) # True — значения равны
print(a is b) # False — это два разных объекта
Правило: == сравнивает значения, is — идентичность. Для проверки на None используйте is None, а не == None.
Списки и кортежи: изменяемое против неизменяемого
Список и кортеж хранят упорядоченные последовательности, но список изменяем, а кортеж — нет. Попытка присвоить элемент кортежа вызовет ошибку:
t = (1, 2, 3)
t[0] = 99 # TypeError: 'tuple' object does not support item assignment
Важная тонкость: неизменяемость кортежа поверхностная. Если внутри кортежа лежит список, сам список менять можно — идентичность кортежа при этом не меняется:
t = (1, 2, [3, 4])
t[2].append(5)
print(t) # (1, 2, [3, 4, 5])
Поэтому такой кортеж уже нельзя использовать ключом словаря или элементом множества — он не хешируется.
Ловушка: изменяемый аргумент по умолчанию
Самая частая ошибка, связанная с изменяемыми типами. Значение по умолчанию вычисляется один раз — при определении функции, а не при каждом вызове. Изменяемый объект по умолчанию будет общим для всех вызовов:
def add_item(item, bucket=[]):
bucket.append(item)
return bucket
print(add_item("a")) # ['a']
print(add_item("b")) # ['a', 'b'] — а ожидали ['b']
Список bucket создался один раз и «запомнил» прошлые вызовы. Правильный шаблон — использовать None как маркер и создавать новый объект внутри функции:
def add_item(item, bucket=None):
if bucket is None:
bucket = []
bucket.append(item)
return bucket
print(add_item("a")) # ['a']
print(add_item("b")) # ['b']
Хешируемость и ключи словарей
Ключами словаря и элементами множества могут быть только хешируемые объекты, а хешируемы, как правило, неизменяемые типы. Кортеж подойдёт, список — нет:
d = {(1, 2): "точка"} # OK — кортеж хешируем
d = {[1, 2]: "точка"} # TypeError: unhashable type: 'list'
Это прямое следствие изменяемости: если бы ключ можно было менять, хеш-таблица «потеряла» бы запись.
Как безопасно копировать изменяемые объекты
Присваивание не копирует объект — оно создаёт новую ссылку на тот же объект. Для копий используйте модуль copy: copy.copy() делает поверхностную копию, copy.deepcopy() — глубокую, с рекурсивным копированием вложенных структур.
import copy
original = [[1, 2], [3, 4]]
shallow = copy.copy(original) # внешний список новый, вложенные — общие
deep = copy.deepcopy(original) # полностью независимая копия
original[0].append(99)
print(shallow) # [[1, 2, 99], [3, 4]] — вложенный список общий
print(deep) # [[1, 2], [3, 4]] — не затронут
Лучшие практики
- Используйте неизменяемые типы (кортежи, frozenset) для данных, которые не должны меняться, — это исключает случайные модификации и упрощает отладку.
- Никогда не задавайте изменяемый объект (
[],{}) как значение аргумента по умолчанию — применяйте шаблон сNone. - Помните, что передача изменяемого объекта в функцию даёт функции доступ к оригиналу; если менять его нельзя — передавайте копию.
- Для ключей словарей и элементов множеств берите неизменяемые значения.
- Сравнивайте значения через
==, идентичность — черезis.
Эти правила особенно важны, когда вы пишете код на Python для анализа данных или обучения моделей — там структуры данных живут долго и разделяются между функциями. Если только начинаете, полезно сперва разобраться, как выбрать первый язык программирования, а затем углубиться в полезные библиотеки для Python и практику на реальных проектах вроде искусственного интеллекта на Python с TensorFlow и Keras.
Часто задаваемые вопросы
Какие типы данных в Python изменяемые, а какие неизменяемые?
Изменяемые: list, dict, set, bytearray. Неизменяемые: int, float, complex, bool, str, tuple, bytes, frozenset. Изменяемые можно менять на месте, неизменяемые — нет.
Кортеж (tuple) изменяемый или нет?
Кортеж неизменяемый: переприсвоить его элементы нельзя. Но если внутри лежит изменяемый объект (например, список), содержимое этого объекта поменять можно, и тогда кортеж перестаёт быть хешируемым.
Почему нельзя использовать список как ключ словаря?
Ключ словаря должен быть хешируемым, а список изменяем и потому не хешируется. Вместо списка используйте кортеж из неизменяемых элементов.
В чём разница между == и is?
Оператор == сравнивает значения объектов, а is — их идентичность (один это объект в памяти или разные). Два разных списка с одинаковым содержимым дадут == True, но is False.
Как правильно скопировать изменяемый объект?
Простое присваивание создаёт лишь новую ссылку. Для независимой копии применяйте copy.copy() (поверхностная) или copy.deepcopy() (глубокая, для вложенных структур).
- Освой нейросеть Perplexity и узнай, как пользоваться функционалом остальных ИИ в одном
- УЧАСТВОВАТЬ ЗА 0 РУБ.
- Расскажем, как получить подписку
- ПОКАЖЕМ, КАК РАЗВЕРНУТЬ МОДЕЛЬ нейросеть DEEPSEEK R1 ПРЯМО НА СВОЁМ КОМПЬЮТЕРЕ