Проанализируйте следующий фрагмент Python: "a = [1,2,3]; b = a; b.append(4); print(a)" — объясните поведение ссылки/копирования, когда это опасно и как правильно сделать независимую копию
Кратко объясню поведение и варианты копирования. Что происходит в фрагменте a = [1,2,3][1,2,3][1,2,3]; b = a; b.append(4)(4)(4); print(a) - Присвоение `b = a` не создает новую копию списка — обе переменные указывают на один и тот же объект. Поэтому `print(a)` выведет [1,2,3,4][1,2,3,4][1,2,3,4]. Почему так происходит - Списки в Python — изменяемые (mutable) объекты. Присвоение копирует ссылку на объект, а не сам объект. Когда это опасно - Когда вы ожидаете независимую копию и модификации через одну переменную не должны влиять на другую. - Особенно опасно при вложенных структурах (список списков): поверхностное копирование оставляет общими вложенные объекты. Как правильно сделать копию - Поверхностная копия (копирует только верхний уровень): - Срез: `b = a[:]` - Конструктор: `b = list(a)` - Модуль copy: `import copy; b = copy.copy(a)` Эти варианты подходят, если элементы — неизменяемые или вложенности нет. - Глубокая копия (рекурсивно копирует вложенные изменяемые объекты): - `import copy; b = copy.deepcopy(a)` Примеры (ожидаемый вывод): - После `a = [1,2,3][1,2,3][1,2,3]; b = a; b.append(4)(4)(4)` -> `a` становится [1,2,3,4][1,2,3,4][1,2,3,4]. - При поверхностной копии: `a = [[1]]; b = a[:] ; b[0].append(2)` -> и `a` и `b` содержат `[[1,2]]` (вложенный список общий). - При глубокой копии: `b = copy.deepcopy(a)` — изменения в `b` не затронут `a`. Замечание - Для неизменяемых типов (int, str, tuple) присвоение безопасно, потому что объекты нельзя изменить in-place.
Что происходит в фрагменте
a = [1,2,3][1,2,3][1,2,3]; b = a; b.append(4)(4)(4); print(a)
- Присвоение `b = a` не создает новую копию списка — обе переменные указывают на один и тот же объект. Поэтому `print(a)` выведет [1,2,3,4][1,2,3,4][1,2,3,4].
Почему так происходит
- Списки в Python — изменяемые (mutable) объекты. Присвоение копирует ссылку на объект, а не сам объект.
Когда это опасно
- Когда вы ожидаете независимую копию и модификации через одну переменную не должны влиять на другую.
- Особенно опасно при вложенных структурах (список списков): поверхностное копирование оставляет общими вложенные объекты.
Как правильно сделать копию
- Поверхностная копия (копирует только верхний уровень):
- Срез: `b = a[:]`
- Конструктор: `b = list(a)`
- Модуль copy: `import copy; b = copy.copy(a)`
Эти варианты подходят, если элементы — неизменяемые или вложенности нет.
- Глубокая копия (рекурсивно копирует вложенные изменяемые объекты):
- `import copy; b = copy.deepcopy(a)`
Примеры (ожидаемый вывод):
- После `a = [1,2,3][1,2,3][1,2,3]; b = a; b.append(4)(4)(4)` -> `a` становится [1,2,3,4][1,2,3,4][1,2,3,4].
- При поверхностной копии: `a = [[1]]; b = a[:] ; b[0].append(2)` -> и `a` и `b` содержат `[[1,2]]` (вложенный список общий).
- При глубокой копии: `b = copy.deepcopy(a)` — изменения в `b` не затронут `a`.
Замечание
- Для неизменяемых типов (int, str, tuple) присвоение безопасно, потому что объекты нельзя изменить in-place.