← Назад к вопросам

Контейнерный типы данных изменяемый или неизменяемый

2.3 Middle🔥 151 комментариев
#DevOps и инфраструктура

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Изменяемость контейнерных типов данных в Python

Контейнерные типы Python делятся на две категории: изменяемые (mutable) и неизменяемые (immutable).

Таблица контейнерных типов

ТипКатегорияОписание
listMutableУпорядоченная коллекция, можно менять элементы
dictMutableКлюч-значение, можно добавлять/удалять пары
setMutableНеупорядоченное множество, можно добавлять/удалять элементы
tupleImmutableУпорядоченная коллекция, нельзя менять элементы
frozensetImmutableНеизменяемое множество
strImmutableСтрока, нельзя менять символы
bytesImmutableБайтовая последовательность, нельзя менять значения
bytearrayMutableИзменяемая версия bytes

Изменяемые (mutable) контейнеры

List — изменяемый список

# Создание
my_list = [1, 2, 3]

# Изменение элементов (исходный объект меняется)
my_list[0] = 99
print(my_list)  # [99, 2, 3]

# Добавление элементов
my_list.append(4)
print(my_list)  # [99, 2, 3, 4]

# Удаление
my_list.pop()
print(my_list)  # [99, 2, 3]

# Расширение
my_list.extend([7, 8, 9])
print(my_list)  # [99, 2, 3, 7, 8, 9]

# Проверка того же объекта
a = [1, 2, 3]
id_before = id(a)
a[0] = 100
id_after = id(a)
print(id_before == id_after)  # True — это тот же объект!

Dict — изменяемый словарь

my_dict = {'name': 'John', 'age': 30}

# Изменение значения
my_dict['age'] = 31
print(my_dict)  # {'name': 'John', 'age': 31}

# Добавление нового ключа
my_dict['city'] = 'Moscow'
print(my_dict)  # {'name': 'John', 'age': 31, 'city': 'Moscow'}

# Удаление ключа
del my_dict['city']
print(my_dict)  # {'name': 'John', 'age': 31}

# Объект меняется на месте
a = {'key': 'value'}
a['key'] = 'new_value'
print(id(a))  # Тот же id

Set — изменяемое множество

my_set = {1, 2, 3}

# Добавление элемента
my_set.add(4)
print(my_set)  # {1, 2, 3, 4}

# Удаление элемента
my_set.remove(2)
print(my_set)  # {1, 3, 4}

# Объект меняется на месте
a = {1, 2, 3}
a.add(999)
print(id(a))  # Тот же id

Bytearray — изменяемые байты

my_bytes = bytearray(b'Hello')

# Изменение байта
my_bytes[0] = ord('J')
print(my_bytes)  # bytearray(b'Jello')

# Объект меняется на месте
a = bytearray(b'test')
a[0] = ord('T')
print(id(a))  # Тот же id

Неизменяемые (immutable) контейнеры

Tuple — неизменяемый кортеж

my_tuple = (1, 2, 3)

# ❌ Попытка изменить — ОШИБКА
my_tuple[0] = 99
# TypeError: 'tuple' object does not support item assignment

# ❌ Попытка добавить — ОШИБКА
my_tuple.append(4)
# AttributeError: 'tuple' object has no attribute 'append'

# ✅ Создание нового кортежа
my_tuple = (1, 2, 3) + (4,)
print(my_tuple)  # (1, 2, 3, 4) — это НОВЫЙ объект
print(id(my_tuple))  # Другой id

Frozenset — неизменяемое множество

my_frozenset = frozenset({1, 2, 3})

# ❌ Попытка добавить — ОШИБКА
my_frozenset.add(4)
# AttributeError: 'frozenset' object has no attribute 'add'

# ✅ Создание нового frozenset
my_frozenset = my_frozenset | {4}
print(my_frozenset)  # frozenset({1, 2, 3, 4}) — это НОВЫЙ объект

# Frozenset можно использовать как ключ словаря
my_dict = {frozenset({1, 2}): 'value'}  # Это сработает

# А обычный set нельзя
my_dict = {set({1, 2}): 'value'}  # TypeError

Str — неизменяемая строка

my_str = 'Hello'

# ❌ Попытка изменить — ОШИБКА
my_str[0] = 'J'
# TypeError: 'str' object does not support item assignment

# ✅ Создание новой строки
my_str = 'J' + my_str[1:]
print(my_str)  # 'Jello' — это НОВЫЙ объект

# Методы строк возвращают новые строки
a = 'hello'
b = a.upper()
print(a)  # 'hello' — исходная не изменилась
print(b)  # 'HELLO' — новая строка
print(id(a) == id(b))  # False

Bytes — неизменяемые байты

my_bytes = b'Hello'

# ❌ Попытка изменить — ОШИБКА
my_bytes[0] = ord('J')
# TypeError: 'bytes' object does not support item assignment

# ✅ Создание новых байтов
my_bytes = b'J' + my_bytes[1:]
print(my_bytes)  # b'Jello' — это НОВЫЙ объект

Важный момент: вложенные контейнеры

Tuple содержит изменяемый список

my_tuple = (1, 2, [3, 4, 5])

# ❌ Менять сам кортеж нельзя
my_tuple[0] = 99  # TypeError

# ✅ Но содержимое изменяемого контейнера внутри — можно
my_tuple[2][0] = 99
print(my_tuple)  # (1, 2, [99, 4, 5])

# Причина: tuple неизменяем на уровне структуры,
# но не отвечает за содержимое внутренних объектов

Frozenset содержит только неизменяемое

# ❌ Frozenset не может содержать список
my_frozenset = frozenset({(1, 2), [3, 4]})  # TypeError

# Потому что list изменяем и может быть изменён
# Это нарушит целостность frozenset

# ✅ Только неизменяемое
my_frozenset = frozenset({(1, 2), (3, 4)})  # Ok

Практическое применение

Когда использовать immutable

# 1. Как ключи в словаре (tuple можно, list нельзя)
config = {
    (1, 2): 'point A',        # ✅ Tuple работает
    (3, 4): 'point B',
}

config = {
    [1, 2]: 'point A',        # ❌ TypeError: unhashable type
}

# 2. В множествах
cached_ids = {1, 2, 3}                    # ✅ Set работает
cached_ids = {(1, 2), (3, 4)}             # ✅ Tuple работает
cached_ids = {[1, 2], [3, 4]}             # ❌ TypeError

# 3. Как параметр функции (более безопасно)
def process_data(data: tuple):
    # Функция уверена, что data не изменится внутри
    return len(data)

# 4. Для потокобезопасности
from threading import Thread

data = (1, 2, 3)  # ✅ Безопасно для многопоточности

def worker(data):
    for x in data:  # Можно читать, не боясь что изменится
        print(x)

Thread(target=worker, args=(data,)).start()

Когда использовать mutable

# 1. Нужна хорошая производительность
items = []  # Добавлять элементы в список — эффективнее
for i in range(1000000):
    items.append(i)

# Чем каждый раз создавать новый tuple
my_tuple = ()
for i in range(1000000):
    my_tuple = my_tuple + (i,)  # Создаётся новый объект каждый раз!

# 2. Нужна структура типа словаря
user = {}
user['name'] = 'John'
user['age'] = 30

Проверка изменяемости

# Функция для проверки
def is_mutable(obj):
    """Проверяет, изменяем ли объект"""
    try:
        # Пытаемся хешировать объект
        hash(obj)
        return False  # Если хеш успешен, то immutable
    except TypeError:
        return True   # Если ошибка, то mutable

print(is_mutable([1, 2, 3]))       # True (list mutable)
print(is_mutable((1, 2, 3)))       # False (tuple immutable)
print(is_mutable({1, 2, 3}))       # True (set mutable)
print(is_mutable(frozenset([1])))  # False (frozenset immutable)
print(is_mutable('hello'))         # False (str immutable)

Вывод

Контейнерные типы Python делятся на:

Mutable (изменяемые):

  • list — список
  • dict — словарь
  • set — множество
  • bytearray — изменяемые байты

Можно менять, добавлять, удалять элементы на месте. Хешировать нельзя.

Immutable (неизменяемые):

  • tuple — кортеж
  • frozenset — неизменяемое множество
  • str — строка
  • bytes — байты

Нельзя менять элементы, но можно создавать новые объекты. Можно использовать как ключи словаря и элементы множеств.

Выбор между ними зависит от того, нужна ли изменяемость, производительность и потокобезопасность.