Глубокое и поверхностное копирование в Python

Spread the love

Введение

В этом уроке мы собираемся обсудить поверхностное (shallow) и глубокое (deep) копирование с помощью примеров на Python. Мы рассмотрим определение глубокого и поверхностного копирования, а также их реализации на языке Python, чтобы оценить основные различия между двумя типами копирования.

Во многих программах, которые мы пишем, нам часто приходится копировать объекты по какой либо причине, например, из-за улучшения вычислительной эффективности. Есть два способа сделать это: сделать полную копию или поверхностную копию. Прежде чем мы обсудим различия между ними, давайте сначала рассмотрим, что такое глубокое и поверхностное копирование.

Глубокое копирование в Python

Глубокая копия создает новую и отдельную копию всего объекта или списка со своим уникальным адресом памяти. Это означает, что любые изменения, внесенные вами в новую копию объекта или списка, не будут отражаться в исходной. Этот процесс происходит следующим образом, сначала создается новый список или объект, а затем рекурсивно копируя все элементы из исходного в новый.

Короче говоря, оба объекта становятся полностью независимы друг от друга. Это похоже на концепцию передачи по значению в таких языках, как C ++, Java и C #.

Пример глубокого копирования

Для реализации концепции глубокого копирования в Python мы будем использовать модуль copy.

Допустим, у нас есть список с именем result_A, который содержит оценки ученика A по 3 предметам, и мы хотим создать точно такой же список результатов и для ученика B. Мы сделаем глубокую копию списка result_A и позже сделаем несколько изменений в этой копии, чтобы посмотреть на оценки ученика B.

Пример 1:

# Program 1 - Deep Copy
import copy

result_A = [90, 85, 82] # Student A grades  
result_B = copy.deepcopy(result_A) # Student B grades (copied from A)

print(result_A)  
print(result_B)  

В приведенном выше сценарии мы используем метод deepcopy из модуля copy, чтобы скопировать список result_A в result_B. Далее мы печатаем содержимое обоих списков на экране.

[90, 85, 82]
[90, 85, 82]

Как видите, списки идентичны. Позже в этой статье мы рассмотрим, как они отличается от результата поверхностного копирования.

Поверхностное копирование в Python

Поверхностное копирование также создает отдельный новый объект или список, но вместо копирования дочерних элементов в новый объект, оно просто копирует ссылки на их адреса памяти. Следовательно, если вы сделаете изменение в исходном объекте, оно будет отражено в скопированном объекте, и наоборот. Короче говоря, обе копии зависят друг от друга. Это похоже на концепцию передачи по ссылке в таких языках программирования, как C ++, C # и Java.

Пример поверхностного копирования

Чтобы реализовать это в Python, мы снова будем использовать модуль copy, но на этот раз мы будем использовать функцию copy.

Давайте воспользуемся тем же списком.

Пример 2:

# Program 2 - Shallow Copy
import copy

result_A = [95, 85, 82]  
result_B = copy.copy(result_A)

print(result_A)  
print(result_B)  

В приведенном выше сценарии мы используем метод copy из модуля copy, чтобы сделать поверхностную копию списка result_A, который мы назвали result_B. Далее содержимое обоих списков было напечатано на консоли.

[90, 85, 82]
[90, 85, 82]

Опять же, такие же списки, как и ожидалось. Далее мы объясним разницу между результатами, которые мы получаем от функций copy и deepcopy.

Разница между глубоким и поверхностным копированием

Теперь, когда мы обсудили, что такое поверхностное и глубокое копирование, пришло время поговорить о разнице между ними. По сути, есть только два основных различия, и они связаны друг с другом:

  1. При глубоком копирование новый объект хранит копии значений объекта, тогда как при поверхностным копирование новый объект хранить ссылки на исходный адрес памяти
  2. Глубокая копия не отражает изменения, внесенные в новый/скопированный объект в исходном объекте; в то время как поверхностная копия отражает

Прежде чем мы перейдем к примеру в котором будет рассмотрена разница, я бы хотел, чтобы вы представили аналогию для сценария примера. Допустим, два человека хотят поделиться напитком; у них два пустых стакана и две соломинки. Они могут поделиться напитком двумя способами:

  1. Поместить напиток в один стакан, и поместить обе соломинки в этот стакан для совместного использования.
  2. Поместить напиток в оба стакана, и поместить одну соломинку в каждый стакан

Первый сценарий – сценарий это аналогия поверхностного копирования. Обе переменные/экземпляры используют одну и ту же ячейку памяти для своих операций. Второй сценарий – сценарий глубокого копирования. Обе переменные/экземпляры используют две разные области памяти для своих операций.

Пример сравнения

Чтобы прояснить разницу, давайте использовать эту информацию в наших двух приведенных выше примерах, начиная с примера 1.

Выше мы создали список result_A и сделали его полную копию с именем result_B. Давайте попробуем изменить содержимое в result_B и посмотрим, повлияет ли это на содержимое result_A.

# This code is an extension of Program 1.
# Copy and paste the below lines in your Example 1

# Change first subject's marks to 30
result_B[0] = 30

print("Original List: ")  
print(result_A)  
print("Deep Copy:")  
print(result_B)  
Original List:  
[90, 10, 85, 82]
Deep Copy:  
[30, 10, 85, 82]

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

Теперь давайте попробуем то же самое с примером 2 – поверхностное копирование.

# This code is an extension of Program 2.
# Copy and paste the below lines in Example 2

result_B[0] = 30

print("Original List: ")  
print(result_A)  
print("Shallow Copy:")  
print(result_B)  
# Expected Outcome: Original list gets modified as well
Original List:  
[30, 10, 85, 82]
Shallow Copy:  
[30, 10, 85, 82]

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

Заключение

В этом посте мы говорили о том, что такое поверхностное и глубокое копирование и как они реализуются на языке Python, используя модуль «copy». Мы использовали две его функции, а именно: copy и deepcopy. Кроме того, мы обсудили два основных различия между поверхностной и глубокой копией, а также реализовали поверхностное и глубокое копирование в python, чтобы лучше понять эти различия.

Оригинал: Deep vs Shallow Copies in Python

Была ли вам полезна эта статья?
[36 / 4.1]

Spread the love
Подписаться
Уведомление о
guest
8 Комментарий
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Алексей
Алексей
4 лет назад

А разве при поверхностном копировании с помощью импортированной функции copy.copy(), ссылочное копирование происходит не только с элементами списка которые сами являются списком? То есть в вашем примере поверхностного копирования переменные будут ссылаться на два различных объекта, так как ссылочных элементов внутри списка нет и изменения первого не затронут изменение второго.

Илья
Илья
4 лет назад
Reply to  Алексей

Согласен. По смыслу статьи непонятно, чем тогда copy.copy() отличается от простого присваивания b = a

Виталий
4 лет назад

Вы переводчик, все статьи переводы

Alex
Alex
4 лет назад
Reply to  Виталий

И что? если статьи помогают освоить Python, то какая разница откуда они?
спасибо автору! (даже если он переводчик)

Алмвам
Алмвам
3 лет назад

Автор балбес. Поленился даже свой код проверить. В вашем случае при поверхностном копировании списки будут разные, а не как в вашем коде. Для примера нужно использовать вложенные списки. Ну и кретин!

L.K.
L.K.
2 лет назад
Reply to  Алмвам

А еще он не упомянул, что вложенные классы не копируются даже через copy.deepcopy()

Biba
Biba
2 лет назад
Reply to  L.K.
Олег
Олег
2 месяцев назад
Reply to  Алмвам

Кстати, в конце данной статьи, есть ссылка на оригинальную статью, где все в порядке с примерами, все они содержат вложенные списки )