Присваивание связывает имя с объектом
Пусть список numbers содержит значения пять, два и восемь. После присваивания other = numbers оба имени связаны с одним списком. Если добавить через other число один, при просмотре numbers тоже появится один. Отдельного списка операция присваивания не создала. Полезно мысленно рисовать два ярлыка, прикреплённых к одной коробке. Содержимое коробки меняется независимо от того, через какой ярлык к нему обратились. Такая схема помогает объяснять поведение до запуска программы, а не только замечать его после ошибки.
Отличать изменение объекта от нового присваивания
Добавление элемента через append меняет существующий список. А присваивание имени other совершенно нового списка меняет связь этого имени с объектом. После этого numbers продолжает указывать на прежний список. Это разные операции, хотя в разговоре обе иногда называют изменением переменной. Аналогично метод sort упорядочивает сам список и возвращает None, а функция sorted создаёт новый отсортированный список. Если нужно сохранить исходный порядок, важно выбрать подходящую операцию и не принимать возвращаемое значение изменяющего метода за готовую копию.
Понять границу поверхностной копии
Метод copy у обычного списка создаёт новый внешний список. Если исходный список содержит только целые числа, добавление элемента в копию не добавит его в оригинал. Но при вложенных списках ситуация тоньше. Пусть внешний список содержит два внутренних: один, два и три, четыре. Поверхностная копия создаст другую внешнюю оболочку, сохранив ссылки на те же внутренние списки. Если в первый внутренний список через копию добавить девять, изменение будет видно и через оригинал. Новая оболочка не означает независимости всех вложенных объектов.
Выбирать нужную степень независимости
Глубокое копирование предназначено для рекурсивного копирования составных объектов, но его не стоит применять автоматически к любой задаче. Некоторые данные должны оставаться общими, а некоторые объекты имеют особое поведение при копировании. Иногда достаточно создать новый список простых значений или явно собрать нужную структуру. Перед выбором полезно сформулировать требование: нужно ли менять только порядок элементов, добавлять новые элементы или независимо редактировать вложенные данные? Чем точнее описано ожидаемое поведение, тем проще выбрать операцию и проверить её на небольшом примере.
Попробуйте на практике
Проследите изменения на бумаге или в уже доступном интерпретаторе Python. Используйте только учебные списки, без настоящих файлов и пользовательских данных.
- Создайте список a со значениями пять, два и восемь и свяжите имя b с тем же списком присваиванием b = a.
- Добавьте через b число один и запишите содержимое a.
- Создайте c = a.copy(), добавьте в c число девять и сравните оба списка.
- Отдельно создайте вложенный список из двух строк: один, два и три, четыре; сделайте его поверхностную копию.
- Добавьте девять в первую внутреннюю строку через копию и объясните, почему изменение видно в оригинале.
Как проверить результат. После второго шага a содержит пять, два, восемь и один. Добавление девяти во внешний список c не меняет a. Но изменение общего внутреннего списка отражается в обеих вложенных структурах.
Частые вопросы
Одинаковое содержимое означает, что это один объект?
Нет. Два независимых списка могут содержать одинаковые значения. Равенство содержимого и тождество объекта являются разными проверками.
Поверхностная копия всегда неправильна?
Нет. Она подходит, когда нужна отдельная внешняя коллекция, а совместное использование вложенных объектов допустимо. Ошибка возникает при несовпадении этого поведения с ожиданиями программы.
Самостоятельный разбор темы. Содержание конкретной обучающей программы здесь не представлено.