Использование функций copy и deepcopy в Python

Использование функций copy и deepcopy в Python

В этой статье я расскажу, как скопировать объект с помощью мелкой копии и глубокой копии в Python.

Введение

При программировании нам нужно скопировать существующие данные. Когда мы присваиваем переменную другому оператору, то оператор присваивания не копирует объект, а просто создает новую ссылку на тот же объект.

Давайте приступим к рассмотрению конкретных примеров.

Как использовать функцию copy в Python?

Мелкая копия — это функция, используемая для создания копии существующего объекта коллекции. Когда мы пытаемся скопировать объект коллекции с помощью неглубокой копии, эта функция создает новый объект коллекции и сохраняет ссылки на элементы исходного объекта.

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

Метод copy принимает исходный объект коллекции в качестве входных данных и создает новый объект коллекции со ссылкой на элементы исходного объекта коллекции. Затем он возвращает ссылку на новый объект коллекции.

В следующем примере я создам копию данного словаря Python с помощью метода copy:

import copy

data = {1: 5, 2: 6, 3: 7, 4: 8}
print("Оригинальный словарь:")
print(data)
new_data = copy.copy(data)
print("Новый словарь:")
print(new_data)

Вывод программы:

Оригинальный словарь:
{1: 5, 2: 6, 3: 7, 4: 8}
Новый словарь:
{1: 5, 2: 6, 3: 7, 4: 8}

В выходных данных мы видим, что мы создали такой же словарь, как и исходный словарь, приведенный выше.

Как работает неглубокое копирование?

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

Рассмотрим пример:

import copy

data = {1: 5, 2: 6, 3: 7, 4: 8}
print("Оригинальный словарь:")
print(data)
new_data = copy.copy(data)
print("Новый словарь:")
print(new_data)
new_data[1] = 99
print("Оригинальный словарь после изменения:")
print(data)
print("Новый словарь после изменения:")
print(new_data)

Вывод программы:

Оригинальный словарь:
{1: 5, 2: 6, 3: 7, 4: 8}
Новый словарь:
{1: 5, 2: 6, 3: 7, 4: 8}
Оригинальный словарь после изменения:
{1: 5, 2: 6, 3: 7, 4: 8}
Новый словарь после изменения:
{1: 99, 2: 6, 3: 7, 4: 8}

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

Например:

import copy

data = {1: 5, 2: 6, 3: 7, 4: 8}
print("Оригинальный словарь:")
print(data)
new_data = copy.copy(data)
print("Новый словарь:")
print(new_data)
data[1] = 99
print("Оригинальный словарь после изменения:")
print(data)
print("Новый словарь после изменения:")
print(new_data)

Вывод программы:

Оригинальный словарь:
{1: 5, 2: 6, 3: 7, 4: 8}
Новый словарь:
{1: 5, 2: 6, 3: 7, 4: 8}
Оригинальный словарь после изменения:
{1: 99, 2: 6, 3: 7, 4: 8}
Новый словарь после изменения:
{1: 5, 2: 6, 3: 7, 4: 8}

Точно так же, когда мы добавляем какой-либо элемент к исходному объекту, он не будет иметь никакого влияния на новый объект.

Ниже пример:

import copy

data = {1: 5, 2: 6, 3: 7, 4: 8}
print("Оригинальный словарь:")
print(data)
new_data = copy.copy(data)
print("Новый словарь:")
print(new_data)
data[7] = 99
print("Оригинальный словарь после изменения:")
print(data)
print("Новый словарь после изменения:")
print(new_data)

Вывод программы:

Оригинальный словарь:
{1: 5, 2: 6, 3: 7, 4: 8}
Новый словарь:
{1: 5, 2: 6, 3: 7, 4: 8}
Оригинальный словарь после изменения:
{1: 5, 2: 6, 3: 7, 4: 8, 7: 99}
Новый словарь после изменения:
{1: 5, 2: 6, 3: 7, 4: 8}

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

Это можно увидеть в следующем примере:

import copy

data = {1: 5, 2: 6, 3: 7, 4: 8, 5: {10: 11}}
print("Оригинальный словарь:")
print(data)
new_data = copy.copy(data)
print("Новый словарь:")
print(new_data)
data[5][10] = 99
print("Оригинальный словарь после изменения:")
print(data)
print("Новый словарь после изменения:")
print(new_data)

Вывод программы:

Оригинальный словарь:
{1: 5, 2: 6, 3: 7, 4: 8, 5: {10: 11}}
Новый словарь:
{1: 5, 2: 6, 3: 7, 4: 8, 5: {10: 11}}
Оригинальный словарь после изменения:
{1: 5, 2: 6, 3: 7, 4: 8, 5: {10: 99}}
Новый словарь после изменения:
{1: 5, 2: 6, 3: 7, 4: 8, 5: {10: 99}}

При копировании объекта с помощью метода copy.copy создается только копия объекта, передаваемая в качестве параметра методу copy. Элементы внутри объекта не копируются, копируются только ссылки на элементы.

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

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

Как использовать deepcopy в Python?

Чтобы избежать проблемы, обсуждаемой при выполнении неглубокого копирования, мы будем использовать метод deepcopy. Метод deepcopy рекурсивно создает копию каждого элемента объекта и не копирует ссылки.

Это можно сделать следующим образом:

import copy

data = {1: 5, 2: 6, 3: 7, 4: {10: 11}}
print("Оригинальный словарь:")
print(data)
new_data = copy.deepcopy(data)
print("Копия словаря:")
print(new_data)

Вывод программы:

Оригинальный словарь:
{1: 5, 2: 6, 3: 7, 4: {10: 11}}
Копия словаря:
{1: 5, 2: 6, 3: 7, 4: {10: 11}}

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

Пример ниже:

import copy

data = {1: 5, 2: 6, 3: 7, 4: {8: 9}}
print("Оригинальный словарь:")
print(data)
new_data = copy.deepcopy(data)
print("Копия словаря:")
print(new_data)
data[4][8] = 99
print("Оригинал после изменения:")
print(data)
print("Копия после изменения:")
print(new_data)

Вывод программы:

Оригинальный словарь:
{1: 5, 2: 6, 3: 7, 4: {8: 9}}
Копия словаря:
{1: 5, 2: 6, 3: 7, 4: {8: 9}}
Оригинал после изменения:
{1: 5, 2: 6, 3: 7, 4: {8: 99}}
Копия после изменения:
{1: 5, 2: 6, 3: 7, 4: {8: 9}}

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

Заключение

В этой статье вы узнали о неглубоком копировании и глубоком копировании в Python.

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

Егор Егоров

Программирую на Python с 2017 года. Люблю создавать контент, который помогает людям понять сложные вещи. Не представляю жизнь без непрерывного цикла обучения, спорта и чувства юмора.

Ссылка на мой github есть в шапке. Залетай.

Оцените автора
Егоров Егор
Добавить комментарий

  1. Alexey

    Здравствуйте, а как будет работать deepcopy в случае циклической вложенности?

    mainList[0,1]
    mainList.append[mainList]
    shadowList = copy.deepcopy

    Ответить
  2. Елена

    Спасибо, Егор, за такой пошаговый и понятный разбор темы, я только обучаюсь работать в этой сфере, поэтому информация была очень актуальна

    Ответить
    1. Егор Егоров автор

      пожалуйста))

      Ответить