Python: поверхневі та глибокі копії

4 хв. читання

Копії у Python

Можливо, ви вже знайомі з оператором присвоєння =: у багатьох мовах програмування ми використовуємо його для створення копії об'єкта того ж типу даних.

Так само ви можете створювати копії у Python, використовуючи =. Проте цей оператор робить не копію об'єкта, а лише нову змінну із посиланням на один і той же об'єкт.

Розглянемо програму, де створимо список old_list та передамо посилання на об'єкт оператором = до new_list.

Приклад 1: Копіювання з використанням оператора =

old_list = [[1,2,3], [4,5,6], [7,8,'a']]
new_list = old_list

new_list[2][2] = 9

print('Old List: ', old_list)
print('Id of Old List: ', id(old_list))

print('New List: ', new_list)
print('Id of New List: ', id(new_list))

Якщо запустити цю програму, отримаємо таке:

Old List: [[1,2,3], [4,5,6], [7,8,9]]
Id of Old List: 140673303268168

New List: [[1,2,3], [4,5,6], [7,8,9]]
Id of New List: 140673303268168

Як ви бачите, обидві змінні old_list та new_list мають однаковий id: 140673303268168.

Отже, якщо змінити одне зі значень у new_list чи old_list, то зміни відбудуться в обох.

По суті, іноді нам потрібно мати оригінальні значення без змін і лише змінювати нові значення, а іноді навпаки. У Python існує два способи створення копій:

  • поверхневе копіювання;
  • глибоке (повне) копіювання.

Для роботи з ними використовується модуль copy.

Модуль copy

Цей модуль використовується для операцій глибокого та поверхневого копіювання. Припустимо, вам треба скопіювати складний список, наприклад:

import copy
copy.copy(x)
copy.deepcopy(x)

Тут copy() поверне поверхневу копію х. Так само deepcopy() поверне глибоку копію x.

Поверхнева копія

Поверхнева копія створює новий об'єкт, який зберігає посилання на оригінальні елементи.

Отже, поверхневе копіювання не створить нових екземплярів вкладених об'єктів, натомість лише скопіює посилання на них. Це означає, що процес копіювання не повторюється.

Приклад 2: Поверхневе копіювання об'єкта

import copy
old_list = [[1,2,3], [4,5,6], [7,8,9]]
new_list = copy.copy(old_list)

print('Old List: ', old_list)
print('New List: ', new_list)

Вивід буде таким:

Old List: [[1,2,3], [4,5,6], [7,8,9]]
New List: [[1,2,3], [4,5,6], [7,8,9]]

У цій програмі ми бачимо створення вкладеного списку та його поверхневе копіювання методом copy().

Це означає, що буде створений новий та незалежний об'єкт з тим самим контентом. Щоб переконатися у цьому, виведемо обидва у консоль.

Аби перевірити, чи два списки відрізняються, додамо вкладені об'єкти до оригінального.

Приклад 3: Додавання [4,4,4] до old_list через поверхневе копіювання

import copy
old_list = [[1,1,1], [2,2,2], [3,3,3]]
new_list = copy.copy(old_list)

old_list.append([4,4,4])

print('Old List: ', old_list)
print('New List: ', new_list)

Результат:

Old list: [[1, 1, 1], [2, 2, 2], [3, 3, 3], [4, 4, 4]]
New list: [[1, 1, 1], [2, 2, 2], [3, 3, 3]]

Програма показує створення поверхневої копії old_list. new_list містить посилання на оригінальний вкладений об'єкт, що зберігається в old_list. Тоді ми додаємо [4,4,4] в old_list. Цей новий список не копіювався у new_list.

Проте будь-які зміни вкладених об'єктів old_list показуються в new_list.

Приклад 4: Додавання нового вкладеного об'єкта за допомогою copy

import copy

old_list = [[1, 1, 1], [2, 2, 2], [3, 3, 3]]
new_list = copy.copy(old_list)

old_list[1][1] = 'AA'

print("Old list:", old_list)
print("New list:", new_list)

Результат програми:

Old list: [[1, 1, 1], [2, 'AA', 2], [3, 3, 3]]
New list: [[1, 1, 1], [2, 'AA', 2], [3, 3, 3]]

Тут зроблені зміни в old_list

old_list[1][1] = 'AA'

Обидва списки в old_list та new_list з індексом [1][1] були змінені. Це відбувається тому, що обидва списки посилаються на один і той самий об'єкт.

Глибока копія

Глибоке копіювання створює новий об'єкт та рекурсивно додає копії вкладених об'єктів, що є в початкових елементах.

Давайте знову розглянемо приклад 2 — та цього разу скористаємося deepcopy() для формування глибокої копії. Глибоке копіювання створює незалежну копію оригінального об'єкта та всіх вкладених об'єктів.

Приклад 5: Копіювання за допомогою deepcopy()

import copy

old_list = [[1, 1, 1], [2, 2, 2], [3, 3, 3]]
new_list = copy.deepcopy(old_list)

print("Old list:", old_list)
print("New list:", new_list)
Old list: [[1, 1, 1], [2, 2, 2], [3, 3, 3]]
New list: [[1, 1, 1], [2, 2, 2], [3, 3, 3]]

Метод відрізняється від поверхневого копіювання, адже тут зміни, зроблені у вкладених об'єктах old_list, не вплинуть на new_list.

Приклад 6: Додавання нового вкладеного об'єкта у список з deepcopy()

import copy

old_list = [[1, 1, 1], [2, 2, 2], [3, 3, 3]]
new_list = copy.deepcopy(old_list)

old_list[1][0] = 'BB'

print("Old list:", old_list)
print("New list:", new_list)

Результат:

Old list: [[1, 1, 1], ['BB', 2, 2], [3, 3, 3]]
New list: [[1, 1, 1], [2, 2, 2], [3, 3, 3]]

Як бачите, зміни відбулися винятково в old_list. Це означає, що обидва списки повністю незалежні — адже old_list був скопійований рекурсивно.

Помітили помилку? Повідомте автору, для цього достатньо виділити текст з помилкою та натиснути Ctrl+Enter
Codeguida 5.2K
Приєднався: 9 місяців тому
Коментарі (0)

    Ще немає коментарів

Щоб залишити коментар необхідно авторизуватися.

Вхід / Реєстрація