import copy
a = "deepak"
b = 1, 2, 3, 4
c = [1, 2, 3, 4]
d = {1: 10, 2: 20, 3: 30}
a1 = copy.copy(a)
b1 = copy.copy(b)
c1 = copy.copy(c)
d1 = copy.copy(d)
print("immutable - id(a)==id(a1)", id(a) == id(a1))
print("immutable - id(b)==id(b1)", id(b) == id(b1))
print("mutable - id(c)==id(c1)", id(c) == id(c1))
print("mutable - id(d)==id(d1)", id(d) == id(d1))
Я получаю следующие результаты:
immutable - id(a)==id(a1) True
immutable - id(b)==id(b1) True
mutable - id(c)==id(c1) False
mutable - id(d)==id(d1) False
Если я выполняю глубокую копию:
a1 = copy.deepcopy(a)
b1 = copy.deepcopy(b)
c1 = copy.deepcopy(c)
d1 = copy.deepcopy(d)
результаты одинаковы:
immutable - id(a)==id(a1) True
immutable - id(b)==id(b1) True
mutable - id(c)==id(c1) False
mutable - id(d)==id(d1) False
Если я работаю над операциями присваивания:
a1 = a
b1 = b
c1 = c
d1 = d
тогда результаты таковы:
immutable - id(a)==id(a1) True
immutable - id(b)==id(b1) True
mutable - id(c)==id(c1) True
mutable - id(d)==id(d1) True
Может кто-нибудь объяснить, что именно делает различия между копиями? Это связано с изменчивыми и неизменяемыми объектами? Если да, не могли бы вы объяснить это мне?
list_=[[1,2],[3,4]] newlist = list_.copy() list_[0]=[7,8] print(list_) print(newlist)
Всеnewlist
еще отображается[[1, 2], [3, 4]]
. Ноlist_[0]
это список, который является изменчивым.list_[0]
изменчив, но вы не изменяете его. Попробуйlist_[0].append(9)
илиlist_[0][0] = 7
взамен.Для неизменяемых объектов копирование не требуется, поскольку данные никогда не изменятся, поэтому Python использует те же данные; идентификаторы всегда одинаковы. Для изменчивых объектов, поскольку они могут потенциально изменяться, [мелкая] копия создает новый объект.
Глубокая копия связана с вложенными структурами. Если у вас есть список списков, то Deepcopy
copies
и вложенных списков, так что это рекурсивная копия. С помощью просто копирования у вас есть новый внешний список, но внутренние списки являются ссылками.Назначение не копируется. Он просто устанавливает ссылку на старые данные. Поэтому вам нужно скопировать, чтобы создать новый список с тем же содержанием.
источник
With just copy, you have a new outer list but inner lists are references.
Для внутренних списков, повлиял ли на скопированный оригинал? Я создаю список списков, подобныхlist_=[[1,2],[3,4]] newlist = list_.copy() list_[0]=[7,8]
иnewlist
остается тем же, так что внутренний список является ссылками?list_[0][0] = 7
Для неизменяемых объектов создание копии не имеет особого смысла, поскольку они не собираются изменяться. Для изменяемых объектов
assignment
,copy
иdeepcopy
ведет себя по- разному. Давайте поговорим о каждом из них с примерами.Операция присваивания просто назначает ссылку источника на место назначения, например:
Теперь
i
иj
технически относится к тому же списку. Обаi
иj
имеют один и тот же адрес памяти. Любое обновление одного из них будет отражено другим. например:С другой стороны
copy
иdeepcopy
создает новую копию переменной. Таким образом, теперь изменения в исходной переменной не будут отражены в переменной копирования и наоборот. тем не мениеcopy(shallow copy)
, не создает копию вложенных объектов, вместо этого он просто копирует ссылку на вложенные объекты. Deepcopy рекурсивно копирует все вложенные объекты.Некоторые примеры, демонстрирующие поведение
copy
иdeepcopy
:Пример плоского списка с использованием
copy
:Пример вложенного списка с использованием
copy
:Пример плоского списка с использованием
deepcopy
:Пример вложенного списка с использованием
deepcopy
:источник
Давайте посмотрим на графическом примере, как выполняется следующий код:
источник
a, b, c, d, a1, b1, c1 и d1 являются ссылками на объекты в памяти, которые однозначно идентифицируются по их идентификаторам.
Операция присваивания берет ссылку на объект в памяти и присваивает эту ссылку новому имени.
c=[1,2,3,4]
это назначение, которое создает новый объект списка, содержащий эти четыре целых числа, и назначает ссылку на этот объектc
.c1=c
это присвоение, которое принимает ту же ссылку на тот же объект и присваивает этоc1
. Поскольку список является изменяемым, все, что происходит с этим списком, будет видно независимо от того, осуществляете ли вы доступ через негоc
илиc1
потому что они оба ссылаются на один и тот же объект.c1=copy.copy(c)
является «мелкой копией», которая создает новый список и назначает ссылку на новый списокc1
.c
по-прежнему указывает на первоначальный список. Таким образом, если вы измените список вc1
, список, на которыйc
ссылается, не изменится.Концепция копирования не имеет отношения к неизменным объектам, таким как целые числа и строки. Поскольку вы не можете изменять эти объекты, никогда не требуется иметь две копии одного и того же значения в памяти в разных местах. Таким образом, целые числа и строки, а также некоторые другие объекты, к которым концепция копирования не применяется, просто переназначаются. Вот почему ваши примеры
a
иb
приводят к идентичным идентификаторам.c1=copy.deepcopy(c)
это «глубокая копия», но в этом примере она работает так же, как и мелкая копия. Глубокие копии отличаются от мелких копий тем, что мелкие копии будут создавать новую копию самого объекта, но любые ссылки внутри этого объекта сами не будут скопированы. В вашем примере ваш список содержит только целые числа (которые являются неизменяемыми), и, как обсуждалось ранее, их не нужно копировать. Так что «глубокая» часть глубокой копии не применяется. Однако рассмотрим этот более сложный список:e = [[1, 2],[4, 5, 6],[7, 8, 9]]
Это список, который содержит другие списки (вы также можете описать его как двумерный массив).
Если вы запустите «мелкую копию»
e
, копируя ееe1
, вы обнаружите, что идентификатор списка изменяется, но каждая копия списка содержит ссылки на те же три списка - списки с целыми числами внутри. Это означает, что если бы вы делалиe[0].append(3)
, тоe
были бы[[1, 2, 3],[4, 5, 6],[7, 8, 9]]
. Ноe1
также будет[[1, 2, 3],[4, 5, 6],[7, 8, 9]]
. С другой стороны, если вы впоследствии сделалиe.append([10, 11, 12])
,e
будет[[1, 2, 3],[4, 5, 6],[7, 8, 9],[10, 11, 12]]
. Ноe1
все равно будет[[1, 2, 3],[4, 5, 6],[7, 8, 9]]
. Это потому, что внешние списки - это отдельные объекты, каждый из которых изначально содержит три ссылки на три внутренних списка. Если вы измените внутренние списки, вы сможете увидеть эти изменения независимо от того, просматриваете ли вы их в одной или другой копии. Но если вы измените один из внешних списков, как указано выше, тоe
содержит три ссылки на три исходных списка и еще одну ссылку на новый список. Иe1
до сих пор содержит только три оригинальные ссылки.«Глубокая копия» будет не только дублировать внешний список, но также будет входить в списки и дублировать внутренние списки, так что два результирующих объекта не будут содержать ни одной из одинаковых ссылок (что касается изменяемых объектов) , Если бы у внутренних списков были дополнительные списки (или другие объекты, такие как словари) внутри них, они тоже были бы дублированы. Это «глубокая» часть «глубокой копии».
источник
В python, когда мы присваиваем такие объекты, как list, tuple, dict и т. Д. Другому объекту, обычно со знаком '=', python создает копии по ссылке . То есть, допустим, у нас есть список таких списков:
и мы назначаем другой список этому списку, как:
тогда, если мы напечатаем list2 в терминале Python, мы получим это:
Оба list1 и list2 указывают на одну и ту же область памяти, любое изменение любого из них приведет к изменениям, видимым в обоих объектах, т.е. оба объекта указывают на одну и ту же область памяти. Если мы изменим list1 следующим образом:
тогда и list1, и list2 будут:
Теперь перейдем к мелкой копии , когда два объекта копируются с помощью мелкой копии, дочерний объект обоих родительских объектов ссылается на одну и ту же область памяти, но любые дальнейшие новые изменения в любом из скопированных объектов будут независимы друг от друга. Давайте разберемся с этим на небольшом примере. Предположим, у нас есть небольшой фрагмент кода:
обратите внимание, list2 остается неизменным, но если мы сделаем изменения в дочерних объектах, таких как:
тогда и list1, и list2 получат изменения:
Теперь Deep copy помогает создавать совершенно изолированные объекты друг от друга. Если два объекта копируются с помощью Deep Copy, то оба родительских и дочерних объекта будут указывать на другое место в памяти. Пример :
обратите внимание, list2 остается неизменным, но если мы сделаем изменения в дочерних объектах, таких как:
тогда list2 также не будет затронут, так как все дочерние объекты и родительские объекты указывают на другое место в памяти:
Надеюсь, поможет.
источник
Код ниже демонстрирует разницу между назначением, поверхностным копированием с использованием метода копирования, поверхностным копированием с использованием (среза) [:] и глубокой копией. Приведенный ниже пример использует вложенные списки, делая различия более очевидными.
источник
ГИСТ, чтобы взять это: Работа с неглубокими списками (без подсписков, только с отдельными элементами) с использованием «нормального присваивания» вызывает «побочный эффект», когда вы создаете неглубокий список, а затем вы создаете копию этого списка с помощью «нормального присваивания» , Этот «побочный эффект» возникает при изменении любого элемента созданного списка копирования, поскольку он автоматически изменит те же элементы исходного списка. Это когда
copy
пригодится, так как это не изменит исходные элементы списка при изменении копирующих элементов.С другой стороны,
copy
также имеет «побочный эффект», когда у вас есть список, в котором есть списки (sub_lists), иdeepcopy
он решает его. Например, если вы создаете большой список, в котором есть вложенные списки (sub_lists), и вы создаете копию этого большого списка (исходный список). «Побочный эффект» возникает, когда вы изменяете подсписки списка копирования, которые автоматически изменяют подсписки большого списка. Иногда (в некоторых проектах) вы хотите сохранить большой список (ваш первоначальный список) без изменений, и все, что вам нужно, - это сделать копию его элементов (sub_lists). Для этого ваше решение заключается в использованииdeepcopy
которое позаботится об этом «побочном эффекте» и сделает копию без изменения исходного содержимого.Различное поведение
copy
иdeep copy
операции касаются только составных объектов (т. Е. Объектов, которые содержат другие объекты, такие как списки).Вот различия, показанные в этом простом примере кода:
Первый
давайте проверим, как
copy
(поверхностно) себя ведет, создав оригинальный список и копию этого списка:Теперь давайте запустим несколько
print
тестов и посмотрим, как ведет себя оригинальный список по сравнению со списком копий:original_list и copy_list имеют разные адреса
элементы original_list и copy_list имеют одинаковые адреса
sub_elements of original_list и copy_list имеют одинаковые адреса
изменение элементов original_list НЕ изменяет элементы copy_list
изменение элементов copy_list НЕ изменяет элементы original_list
изменение sub_elements original_list автоматически изменяет sub_elements copy_list
изменение sub_elements copy_list автоматически изменяет sub_elements original_list
второй
давайте проверим, как
deepcopy
ведет себя, делая то же самое, что и мыcopy
(создавая оригинальный список и копию этого списка):Теперь давайте запустим несколько
print
тестов и посмотрим, как ведет себя оригинальный список по сравнению со списком копий:original_list и copy_list имеют разные адреса
элементы original_list и copy_list имеют одинаковые адреса
sub_elements в original_list и copy_list имеют разные адреса
изменение элементов original_list НЕ изменяет элементы copy_list
изменение элементов copy_list НЕ изменяет элементы original_list
модификация original_list sub_elements НЕ изменяет copy_list sub_elements
изменение copy_list sub_elements НЕ изменяет original_list sub_elements
источник
Не уверен, упоминалось ли это выше или нет, но очень важно понять, что .copy () создает ссылку на оригинальный объект. Если вы меняете скопированный объект - вы меняете исходный объект. .deepcopy () создает новый объект и выполняет реальное копирование исходного объекта в новый. Изменение нового глубоко скопированного объекта не влияет на исходный объект.
И да, .deepcopy () рекурсивно копирует исходный объект, а .copy () создает ссылочный объект для данных первого уровня исходного объекта.
Таким образом, разница между копированием и ссылками между .copy () и .deepcopy () значительна.
источник
Глубокая копия связана с вложенными структурами. Если у вас есть список списков, то Deepcopy также копирует вложенные списки, поэтому это рекурсивная копия. С помощью просто копирования у вас есть новый внешний список, но внутренние списки являются ссылками. Назначение не копируется. Для Ex
Вывод
[[0, 1, 2, 3, 3], 4, 5] [[0, 1, 2, 3, 3], 4, 5, 3] Копировать метод копировать содержимое внешнего списка в новый список, но внутренний список остается одинаковым для обоих списков, поэтому, если вы сделаете изменения во внутреннем списке любых списков, это повлияет на оба списка.
Но если вы используете Deep copy, то он также создаст новый экземпляр для внутреннего списка.
Вывод
[0, 1, 2, 3] [[0, 1, 2, 3, 3], 4, 5, 3]
источник
источник
a
это не глубокая копияlst
!