← Назад к вопросам
Какие типы данных в Python изменяемые, а какие неизменяемые?
1.0 Junior🔥 231 комментариев
#Python Core
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Изменяемые и неизменяемые типы данных в Python
Изменяемость — это свойство объекта либо изменяться после создания, либо оставаться неизменным. Это различие критично для понимания работы памяти, передачи аргументов функции и поведения переменных в Python.
Неизменяемые типы (Immutable)
Объекты этих типов не могут быть изменены после создания. Любые операции, которые кажутся изменением, на самом деле создают новый объект.
Основные неизменяемые типы:
# 1. int (целые числа)
a = 5
print(id(a)) # адрес в памяти
a = 10
print(id(a)) # ДРУГОЙ адрес (новый объект)
# 2. float (числа с плавающей запятой)
f = 3.14
f = 2.71
# f указывает на новый объект
# 3. str (строки)
s = "Hello"
print(id(s))
s = s + " World" # создаёт новую строку
print(id(s)) # ДРУГОЙ адрес
# 4. tuple (кортежи)
t = (1, 2, 3)
print(id(t))
# t[0] = 5 # TypeError: 'tuple' object does not support item assignment
# 5. bool (булевы значения)
b = True
b = False
# Каждое присваивание указывает на другой объект
# 6. frozenset (неизменяемое множество)
fs = frozenset([1, 2, 3])
# fs.add(4) # AttributeError: 'frozenset' object has no attribute 'add'
# 7. None (None объект)
n = None
# Это синглтон, всегда один и тот же объект
# 8. bytes (неизменяемая последовательность байт)
b = b"hello"
print(id(b))
b = b"hello" + b" world"
print(id(b)) # ДРУГОЙ адрес
# 9. Числовые типы: complex, decimal.Decimal
c = 1 + 2j
c = 3 + 4j # новый объект
Изменяемые типы (Mutable)
Объекты этих типов могут быть изменены без создания нового объекта. Изменение происходит «на месте».
Основные изменяемые типы:
# 1. list (списки)
lst = [1, 2, 3]
print(id(lst))
lst[0] = 10 # изменяем элемент на месте
print(id(lst)) # ТОТ ЖЕ адрес!
lst.append(4)
print(id(lst)) # ТОТ ЖЕ адрес!
# 2. dict (словари)
d = {"a": 1, "b": 2}
print(id(d))
d["a"] = 10 # изменяем значение
print(id(d)) # ТОТ ЖЕ адрес!
d["c"] = 3 # добавляем ключ
print(id(d)) # ТОТ ЖЕ адрес!
# 3. set (множества)
s = {1, 2, 3}
print(id(s))
s.add(4) # добавляем элемент
print(id(s)) # ТОТ ЖЕ адрес!
s.remove(1) # удаляем элемент
print(id(s)) # ТОТ ЖЕ адрес!
# 4. bytearray (изменяемая последовательность байт)
ba = bytearray(b"hello")
print(id(ba))
ba[0] = ord('H')
print(id(ba)) # ТОТ ЖЕ адрес!
# 5. lists, дополнительные методы
lst = [1, 2, 3]
lst.extend([4, 5]) # расширяем
lst.clear() # очищаем
lst.sort() # сортируем
# Все на месте, id не меняется
Сравнение при присваивании
# Неизменяемые — присваивание создаёт ссылку на новый объект
a = "hello"
b = a
print(id(a) == id(b)) # True (пока строка одна и та же)
a = "goodbye"
print(a)
print(b) # "hello" — не изменилась!
print(id(a) == id(b)) # False
# Изменяемые — присваивание создаёт ссылку на один объект
lst1 = [1, 2, 3]
lst2 = lst1
print(id(lst1) == id(lst2)) # True
lst1[0] = 10
print(lst1) # [10, 2, 3]
print(lst2) # [10, 2, 3] — ИЗМЕНИЛАСЬ!
print(id(lst1) == id(lst2)) # True (один объект)
Изменяемые объекты в неизменяемых контейнерах
# Кортеж сам неизменяем, но может содержать изменяемые объекты
t = (1, [2, 3], 4)
print(id(t))
# Не можем изменить сам кортеж
# t[1] = [5, 6] # TypeError
# Но можем изменить список внутри кортежа
t[1][0] = 10
print(t) # (1, [10, 3], 4)
print(id(t)) # ТОТ ЖЕ адрес!
# Словари также могут содержать изменяемые значения
data = {
"name": "Alice",
"hobbies": ["reading", "coding"]
}
data["hobbies"].append("gaming") # изменяем список
print(data)
Последствия для функций
# Неизменяемые — функция не может изменить оригинал
def modify_string(s):
s = s + " modified"
return s
original = "hello"
result = modify_string(original)
print(original) # "hello" — не изменилась
print(result) # "hello modified"
# Изменяемые — функция МОЖЕТ изменить оригинал
def modify_list(lst):
lst.append(4)
return lst
original = [1, 2, 3]
result = modify_list(original)
print(original) # [1, 2, 3, 4] — ИЗМЕНИЛАСЬ!
print(result) # [1, 2, 3, 4]
# Правильный способ (создаём копию)
def modify_list_safely(lst):
new_list = lst.copy() # или lst[:]
new_list.append(4)
return new_list
original = [1, 2, 3]
result = modify_list_safely(original)
print(original) # [1, 2, 3] — не изменилась
print(result) # [1, 2, 3, 4]
Таблица типов данных
| Тип | Изменяемый | Примеры операций |
|---|---|---|
| int | Нет | a = 5; a = 6 (новый объект) |
| float | Нет | f = 3.14; f = 2.71 (новый объект) |
| str | Нет | s = "hi"; s = s + "!" (новый объект) |
| tuple | Нет | t = (1, 2); t[0] = 5 — ошибка |
| frozenset | Нет | fs.add(1) — ошибка |
| bytes | Нет | b[0] = 65 — ошибка |
| list | Да | lst[0] = 5; lst.append(6) |
| dict | Да | d["key"] = val; d.pop("key") |
| set | Да | s.add(1); s.remove(2) |
| bytearray | Да | ba[0] = 65; ba.append(66) |
Хеширование
Неизменяемые типы можно использовать как ключи словаря и в множествах:
# ✅ Неизменяемые — можно хешировать
d = {
"key": "value",
(1, 2): "tuple key",
5: "integer key"
}
s = {"string", 42, ("a", "b")}
# ❌ Изменяемые — нельзя хешировать
d = {
[1, 2]: "value" # TypeError: unhashable type: 'list'
}
s = {{"a": 1}} # TypeError: unhashable type: 'dict'
Лучшие практики
- Знайте, какие типы изменяемые — избегайте неожиданных побочных эффектов
- Копируйте при необходимости — используйте
.copy()или slice - Возвращайте новые объекты — не изменяйте входные параметры
- Документируйте изменяемость — в docstrings указывайте, изменяется ли аргумент
def process_data(data_list):
"""Обрабатывает данные.
Args:
data_list: Список для обработки (будет изменён)
Returns:
Обработанный список
"""
data_list.sort()
return data_list
Понимание изменяемости — это основа для написания надежного Python кода без скрытых ошибок.