Какие типы данных в Python являются изменяемыми (mutable)?

Ответ

Изменяемые (mutable) типы данных в Python позволяют модифицировать содержимое объекта после его создания без создания нового объекта. Это ключевое отличие от неизменяемых (immutable) типов.

Основные встроенные изменяемые типы:

  1. Список (list)

    my_list = [1, 2, 3]
    my_list.append(4)      # Изменяет исходный список: [1, 2, 3, 4]
    my_list[0] = 99        # Изменяет элемент по индексу: [99, 2, 3, 4]
  2. Словарь (dict)

    my_dict = {'a': 1, 'b': 2}
    my_dict['c'] = 3       # Добавляет новую пару ключ-значение
    my_dict['a'] = 100     # Изменяет значение для ключа 'a'
  3. Множество (set)

    my_set = {1, 2, 3}
    my_set.add(4)          # Добавляет элемент: {1, 2, 3, 4}
    my_set.discard(2)      # Удаляет элемент: {1, 3, 4}
  4. Байтовый массив (bytearray)

    barr = bytearray(b'hello')
    barr[0] = 106          # Изменяет байт: bytearray(b'jello')

Почему это важно? Практические последствия:

  • Передача по ссылке: При передаче изменяемого объекта в функцию, изменения внутри функции отражаются на исходном объекте.

    def modify_list(lst):
        lst.append('modified')
    
    original = [1, 2]
    modify_list(original)
    print(original)  # Вывод: [1, 2, 'modified'] !
  • Ключи словаря: Только неизменяемые типы (строки, числа, кортежи) могут быть ключами словаря. Список или множество — не могут.

    valid_key = (1, 2)  # Кортеж (неизменяемый) — можно
    # invalid_key = [1, 2]  # Список (изменяемый) — вызовет TypeError
  • Безопасность в многопоточности: Работа с изменяемыми объектами требует синхронизации (например, через threading.Lock).

Общее правило: Если тип данных позволяет изменить свое содержимое "на месте" (in-place) с помощью методов вроде .append(), .add(), [key] = value или оператора индексации [index] = value, то он изменяемый.

Ответ 18+ 🔞

Давай разберём эту тему про изменяемые типы, а то, блядь, народ часто путается и потом сидит с багами, как дурак на бревне.

Вот смотри, есть в Питоне такие типы, которые, как хитрая жопа, могут менять своё содержимое прямо на месте. Создал объект — и потом его можно пилить, резать, дополнять, и он остаётся тем же самым объектом в памяти. Это и есть изменяемые, или mutable, если по-умному.

Главные герои этой банды:

  1. Список (list) Ну, это как твой холодильник. Закинул туда продукты, а потом можешь достать, добавить новое, а старый сырок заплесневелый выкинуть. Объект-то один и тот же — холодильник.

    my_list = [1, 2, 3]
    my_list.append(4)      # Подкинул четвёрку, холодильник тот же
    my_list[0] = 99        # Заменил единицу на девяносто девять. Всё в том же холодильнике!
  2. Словарь (dict) Представь блокнот с контактами. Записал номер к Машке, потом переписал, когда она сменила номер, добавил новую пару — Витька-алкаш. Блокнот один, а записи в нём пляшут.

    my_dict = {'a': 1, 'b': 2}
    my_dict['c'] = 3       # Добавил новую запись
    my_dict['a'] = 100     # Исправил старую. Блокнот не поменялся, ага.
  3. Множество (set) Это типа мешок с уникальными шариками. Сунул руку, вытащил синий, кинул красный. Мешок тот же, состав другой.

    my_set = {1, 2, 3}
    my_set.add(4)          # Кинул четвёртый шарик
    my_set.discard(2)      # Выкинул двойку нахуй. Мешок цел.
  4. Байтовый массив (bytearray) Ну это уже для продвинутых, типа магнитная лента. Записал "hello", потом перемотал и первую букву подправил.

    barr = bytearray(b'hello')
    barr[0] = 106          # Букву 'h' на 'j' поменял. Лента та же, запись новая.

А теперь, блядь, почему это важно? Лови подводные ебла:

  • Передача по ссылке, ёпта! Самый частый пиздец. Кидаешь список в функцию, думаешь — копию отправил. Ан нет, сука, отправил ссылку на тот же самый объект! Функция его внутри поменяла — и у тебя исходный список ебнулся.

    def modify_list(lst):
        lst.append('modified') # Ага, щас тебя подправлю...
    
    original = [1, 2]
    modify_list(original)
    print(original)  # Смотри-ка, а тут уже [1, 2, 'modified']! Вот тебе и сюрприз.
  • Ключи в словарях. Сюда, дружок, только святые и неизменяемые могут. Список или множество в качестве ключа? Да ты что, охуел? Они же могут поменяться, и словарь весь ебётся. Только строки, числа, кортежи.

    valid_key = (1, 2)  # Кортеж — священная корова, можно.
    # invalid_key = [1, 2]  # Список — изменяемый ублюдок. Вызовет TypeError и посмеётся.
  • Многопоточность. Вот тут вообще пиздец начинается. Если десять потоков лезут в один и тот же список что-то пихать — это гарантированный разъёб. Нужны замки (threading.Lock), чтобы очередь выстроить, а то получится каша, мать её.

Короче, правило простое, как три копейки: Если к объекту можно применить .append(), .add(), [key] = value или [index] = value, и он изменится, не создавая нового уёбка, — он изменяемый. Запомни это, и половина твоих багов испарится, как шашлык на даче у алкаша.