В КУРСЕ?

Разбираемся в теме

Два имени, один список: почему изменение в Python появляется сразу в двух местах

Начинающий программист создаёт список, присваивает его другой переменной и ожидает получить запасной экземпляр. Затем меняет второй список и обнаруживает изменение в первом. В Python такое поведение закономерно: присваивание имени не означает автоматическое копирование объекта. Разобраться помогает схема из имён, стрелок и самих данных.

Имя указывает на объект

Рассмотрим последовательность a = [4, 7], затем b = a. После первого действия существует список из двух чисел, на который указывает имя a. Второе действие связывает имя b с тем же списком. Два имени не создают два независимых контейнера. Если выполнить b.append(9), элемент добавится в общий список. Обращение через a и через b покажет одинаковое содержимое: [4, 7, 9]. Для понимания нарисуйте один прямоугольник с числами и две стрелки к нему. Изменение произошло внутри прямоугольника, а не только возле одного из имён.

Новое связывание отличается от изменения

Теперь представим другую операцию: b = [12]. Она создаёт новый список и связывает с ним имя b. Имя a продолжает указывать на прежний объект. Поэтому после предыдущего примера a по-прежнему показывает [4, 7, 9], а b — [12]. Это различие полезно проговаривать каждый раз: меняется существующий объект или имя начинает указывать на другой? Слова переменная изменилась скрывают оба случая и мешают отладке. Схема со стрелками заставляет уточнить, где именно произошло действие. Она особенно удобна, когда одно значение передаётся между несколькими участками программы. При поиске ошибки полезно записывать состояние сразу после каждой операции, а не только в конце. Тогда видно, в какой момент изменилось содержимое и в какой момент перенаправилась связь. Такой разбор делает неожиданное поведение последовательностью понятных шагов.

Копия списка тоже имеет границы

Для отдельного внешнего списка можно использовать метод copy. После c = a.copy() имена a и c указывают на разные списки. Если в c добавить число, длина a от этого не изменится. Для плоского списка чисел это соответствует привычному ожиданию независимой копии. Но такая копия поверхностная. Если элементы сами являются изменяемыми объектами, например вложенными списками, внутренние объекты могут оставаться общими. Значит, вопрос о копировании нужно задавать по уровням: требуется новый внешний контейнер или независимость всей вложенной структуры? Способ выбирают по задаче, а не по одному знакомому названию метода.

Попробуйте на практике

Предскажите результат учебной последовательности до запуска в интерпретаторе Python.

  1. Начните с a = [4, 7] и b = a; нарисуйте имена и общий список.
  2. Выполните мысленно b.append(9) и запишите, что теперь покажут a и b.
  3. Создайте c = a.copy(), затем выполните c.append(12); запишите содержимое всех трёх имён.
  4. Выполните b = [20] и снова обновите схему; при возможности проверьте предсказание в отдельном учебном интерпретаторе.

Как проверить результат. В конце a содержит [4, 7, 9], b содержит [20], а c содержит [4, 7, 9, 12]. На схеме должны быть три разных списка. Если добавление в c изменило ваш нарисованный a, вы не отделили создание копии от обычного присваивания.

Частые вопросы

Одинаковое содержимое означает, что это один объект?

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

Нужно ли копировать каждый список на всякий случай?

Нет. Иногда общий изменяемый объект нужен по замыслу программы. Лишние копии усложняют понимание и расходуют ресурсы. Важно явно решить, должен ли конкретный участок работать с общими данными или с отдельным экземпляром.

Самостоятельный разбор темы. Содержание конкретной обучающей программы здесь не представлено.

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

Зарегистрироваться
← К списку материалов