В Python оператор присваивания не копирует объект, вместо этого он копирует ссылку на объект и сохраняет в новой переменной, поэтому любые изменения в одной переменной будут отражены в другой переменной.

Пример:

a = [1,2,3,4]
b = a
print('---before change---')
print('a:',a,'b:', b)
a.append(5)
print('---after change---')
print('a:',a,'b:', b)

Вывод:

---before change--- 
a: [1, 2, 3, 4] b: [1, 2, 3, 4]
 ---after change--- 
a: [1, 2, 3, 4, 5] b: [1, 2, 3, 4, 5]

Давайте разберемся с этим лучше с помощью визуализации ниже:

когда выполняется a.append (5), значение 5 будет добавлено к тому же объекту, на который указывали списки a и b, следовательно, значения a и b всегда будут одинаковыми.

В python для копирования объектов у нас есть отдельный модуль под названием «копия». Этот модуль предоставляет две функции для копирования следующих объектов:

  1. copy.copy (x): выполняет неглубокое копирование.
  2. copy.deepcopy (x): выполняет глубокое копирование

Обе функции создадут новый объект и скопируют элементы. Разница между мелким и глубоким копированием относится только к составному объекту. Составной объект - это не что иное, как объект, содержащий другой объект.

Давайте разберемся с этим с помощью примера ниже,

import copy
a = [1,2,3,4,5,[1,2,3,4,5,6,7]]
deep = copy.deepcopy(a)
shallow = copy.copy(a)

«A» - составной объект, потому что это список, содержащий другой список, когда мы вызываем функцию deepcopy, он создает новый объект «a» и новый объект вложенного списка, поэтому все копируется в совершенно новую ячейку памяти.

Когда мы вызываем copy (), он создает неглубокую копию объекта, это означает, что новый объект будет создан, но новый объект не будет создан для вложенного объекта, он будет указывать на тот же вложенный объект исходного объекта. Как показано на диаграмме ниже, пятый элемент как «a», так и «shallow» указывает на один и тот же объект списка.

Если мы изменим исходный объект «а», он не отразится на мелком и глубоком объекте,

a = [1,2,3,4,5,[1,2,3,4,5,6,7]]
b = a
shallow = copy.copy(a)
deep = copy.deepcopy(a)
a.append(10)
print('a:',a, end = '\n')
print('shallow: ',shallow,  end = '\n')
print('deep: ', deep)

Вывод:

a: [1, 2, 3, 4, 5, [1, 2, 3, 4, 5, 6, 7], 10] 
shallow:  [1, 2, 3, 4, 5, [1, 2, 3, 4, 5, 6, 7]] 
deep:  [1, 2, 3, 4, 5, [1, 2, 3, 4, 5, 6, 7]]

Но когда мы модифицируем вложенный объект, изменения будут отражаться в неглубокой копии, но не в глубокой копии.

a = [1,2,3,4,5,[1,2,3,4,5,6,7]]
b = a
shallow = copy.copy(a)
deep = copy.deepcopy(a)
a[5].append(23)
print('a:',a, end = '\n')
print('shallow: ',shallow,  end = '\n')
print('deep: ', deep)

Вывод:

a: [1, 2, 3, 4, 5, [1, 2, 3, 4, 5, 6, 7, 23]] 
shallow:  [1, 2, 3, 4, 5, [1, 2, 3, 4, 5, 6, 7, 23]] 
deep:  [1, 2, 3, 4, 5, [1, 2, 3, 4, 5, 6, 7]]

Вывод:

  1. Неглубокая копия создает новый составной объект, а затем (насколько это возможно) вставляет в него * те же объекты *, что и оригинал.
  2. Глубокая копия создает новый составной объект, а затем рекурсивно вставляет в него * копии * объектов, найденных в оригинале.