В чем разница между изменяемыми и неизменяемыми типами в Python?

Ответ

Изменяемые (mutable) типы данных — это объекты, внутреннее состояние которых можно изменить после их создания. Неизменяемые (immutable) типы данных — это объекты, которые нельзя изменить после создания. Любая операция, которая "модифицирует" такой объект, на самом деле создает новый.

Примеры типов данных

  • Неизменяемые (immutable):

    • int, float, complex, bool
    • str
    • tuple
    • frozenset
  • Изменяемые (mutable):

    • list
    • dict
    • set
    • bytearray

Ключевые отличия на практике

1. Изменение объекта "на месте"

Изменяемый объект можно модифицировать, не создавая новый, что эффективно по памяти.

# list - изменяемый
my_list = [1, 2, 3]
print(f"ID до изменения: {id(my_list)}")
my_list.append(4)
print(f"ID после изменения: {id(my_list)}") # ID объекта не изменился
print(my_list) # [1, 2, 3, 4]

Попытка изменить неизменяемый объект приведет к созданию нового объекта в памяти.

# str - неизменяемый
my_string = "hello"
print(f"ID до изменения: {id(my_string)}")
my_string = my_string + " world"
print(f"ID после изменения: {id(my_string)}") # ID объекта изменился
print(my_string) # "hello world"

2. Хешируемость

Только неизменяемые объекты могут быть использованы в качестве ключей словаря или элементов множества (set), так как их хэш-значение остается постоянным на протяжении всей их жизни.

my_dict = {}
immutable_key = (1, 2) # tuple - неизменяемый
mutable_key = [1, 2]   # list - изменяемый

my_dict[immutable_key] = "value" # OK

try:
    my_dict[mutable_key] = "value"
except TypeError as e:
    print(e) # unhashable type: 'list'

Ответ 18+ 🔞

Ну, вот смотри, объясняю на пальцах, а то у тебя там, сука, в глазах уже квадратики плывут. Есть в Питоне такая дичь — типы данных. И делятся они на две неравные банды.

Первая — изменяемые (mutable). Это такие шустрые ребята, которых можно, грубо говоря, пнуть в жопу, и они изменятся прямо на месте, не создавая нового себя. Внутренности им можно менять, как захочется.

Вторая — неизменяемые (immutable). Это, блядь, святые, неприкасаемые. Создали — и всё, пиши пропало. Любая попытка их "изменить" — это на самом деле создание нового, свеженького объекта, а старый так и будет лежать, как истукан, в своей ячейке памяти. Пиздец как неэффективно, но зато надёжно.

Кто есть кто? Запоминай, а то в жопу получишь.

  • Неизменяемые (святые, но скучные):

    • int, float, complex, bool (циферки да булево говно)
    • str (строка, её не перепишешь)
    • tuple (кортеж, закованный в броню)
    • frozenset (множество, которое заморозили нахуй)
  • Изменяемые (шустрилы и проходимцы):

    • list (список — царь и бог)
    • dict (словарь — всему голова)
    • set (множество обычное)
    • bytearray (это уже для продвинутых извращенцев)

А на практике-то что, блядь?

1. Меняем объект, или "В чём разница, ёпта?"

Вот смотри, как изменяемый список ведёт себя. Как та самая хитрая жопа — вертится, как хочет.

# list — изменяемый, как твои обещания
my_list = [1, 2, 3]
print(f"ID до изменения: {id(my_list)}")
my_list.append(4) # Пнули его в жопу, добавили четвёрку
print(f"ID после изменения: {id(my_list)}") # ID объекта НЕ изменился! Он тот же самый!
print(my_list) # [1, 2, 3, 4]

А теперь строка. Неизменяемая, как совесть у политика. Попробуй её изменить — получишь нового клона.

# str — неизменяемый, как законы физики (почти)
my_string = "hello"
print(f"ID до изменения: {id(my_string)}")
my_string = my_string + " world" # Тут не изменение, а, блядь, создание НОВОЙ строки!
print(f"ID после изменения: {id(my_string)}") # ID объекта ИЗМЕНИЛСЯ! Это уже другой чувак!
print(my_string) # "hello world"

2. Хешируемость, или "Кого пускать в элитный клуб?"

Запомни раз и навсегда, ебать мои старые костыли: только неизменяемые объекты могут быть ключами в словаре (dict) или элементами в множестве (set). Почему? Да потому что их хэш (это такая их паспортная печать) не меняется со временем. А у изменяемого типа сегодня хэш один, завтра — другой, ну нахуй такой ключ нужен?

my_dict = {}
immutable_key = (1, 2) # Кортеж — неизменяемый, святой
mutable_key = [1, 2]   # Список — изменяемый, проходимец

my_dict[immutable_key] = "value" # Всё ок, пропустили в клуб

try:
    my_dict[mutable_key] = "value" # А тут — шмон!
except TypeError as e:
    print(e) # unhashable type: 'list' — "нехэшируемый тип, списка, иди нахуй"

Вот и вся философия. Изменяемые — живут быстро, меняются, рискуют. Неизменяемые — стоят как скала, надёжные, но скучные. Выбирай, с кем тебе по пути.