Приведи примеры изменяемых (mutable) структур данных в Python.

«Приведи примеры изменяемых (mutable) структур данных в Python.» — вопрос из категории Python, который задают на 26% собеседований Data Scientist / ML Инженер. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

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

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

  1. Список (list): Упорядоченная коллекция.

    my_list = [1, 2, 3]
    my_list[0] = 100      # Изменение элемента по индексу
    my_list.append(4)     # Добавление в конец
    my_list.extend([5, 6]) # Расширение списка
    my_list.sort()        # Сортировка на месте
    print(my_list)        # [1, 2, 3, 4, 5, 6]? Нет! [100, 2, 3, 4, 5, 6]
  2. Словарь (dict): Коллекция пар ключ-значение.

    my_dict = {'name': 'Alice', 'age': 30}
    my_dict['age'] = 31          # Изменение значения
    my_dict['city'] = 'Berlin'   # Добавление новой пары
    my_dict.update({'job': 'Engineer'})
    value = my_dict.pop('name')  # Удаление с возвратом значения
    print(my_dict)               # {'age': 31, 'city': 'Berlin', 'job': 'Engineer'}
  3. Множество (set): Неупорядоченная коллекция уникальных элементов.

    my_set = {1, 2, 3}
    my_set.add(4)          # Добавление элемента
    my_set.remove(2)       # Удаление элемента (KeyError если нет)
    my_set.discard(10)     # Безопасное удаление (не вызывает ошибки)
    my_set.clear()         # Очистка всего множества
    print(my_set)          # set()

Важные следствия изменяемости:

  • Присваивание по ссылке: При присваивании new_list = my_list создается не копия, а новая ссылка на тот же объект.

    original = [1, 2, 3]
    alias = original
    alias.append(4)
    print(original)  # [1, 2, 3, 4] - изменился и оригинал!

    Решение: использовать копирование (copy() для поверхностной копии, deepcopy() из модуля copy для вложенных структур).

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

    def append_to(element, target=[]):  # ОПАСНО: target создается один раз!
        target.append(element)
        return target
    
    print(append_to(1))  # [1]
    print(append_to(2))  # [1, 2] - сюрприз!

    Правильный паттерн:

    def append_to(element, target=None):
        if target is None:
            target = []  # Новый список при каждом вызове без аргумента
        target.append(element)
        return target

К другим изменяемым типам относятся bytearray, array.array, объекты collections (например, deque, Counter), а также экземпляры пользовательских классов (по умолчанию).