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
Если я выполняю deepcopy:
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
Может кто-нибудь объяснить, что именно делает разницу между копиями? Это что-то связанное с изменяемым & неизменяемые объекты? Если да, не могли бы вы объяснить это мне?
Обычной операции присваивания будет просто новая переменная по отношению к существующему объекту. Раздел Документы объяснить разницу между мелкой и глубокой копии:
разница между мелкой и глубокой копирования имеет значение только для составные объекты (объекты, которые содержат другие объекты, такие как списки или экземпляры класса):
неполная копия создает новый объект соединения, а затем (по мере возможности) вставляет ссылки на его объекты, найденные в оригинале.
глубокая копия создает новый объект соединения, а затем, рекурсивно, вставки копии в него предметов, найденных в оригинал.
Здесь's немного демонстрации:
import copy
a = [1, 2, 3]
b = [4, 5, 6]
c = [a, b]
Используя обычные действия присваивания для копирования:
d = c
print id(c) == id(d) # True - d is the same object as c
print id(c[0]) == id(d[0]) # True - d[0] is the same object as c[0]
Используя мелкую копию:
d = copy.copy(c)
print id(c) == id(d) # False - d is now a new object
print id(c[0]) == id(d[0]) # True - d[0] is the same object as c[0]
Использование глубокого копирования:
d = copy.deepcopy(c)
print id(c) == id(d) # False - d is now a new object
print id(c[0]) == id(d[0]) # False - d[0] is now a new object
Для неизменяемых объектов, нет необходимости в копировании, потому что данные никогда не будут меняться, так что Python использует те же данные; коды всегда одинаковые. Для изменяемых объектов, поскольку они могут потенциально изменить, [мелкий] копирования создает новый объект.
Глубокие копии, связанные с вложенными структурами. Если у вас есть список списков, то deepcopy копии
вложенные списки, так это рекурсивного копирования. С просто копия, у вас есть новый внешний список, но внутреннее списки ссылок.
Задание не копирует. Он просто создает ссылку на старые данные. Так что вам нужно скопировать, чтобы создать новый список с тем же самым содержанием.
Для неизменяемых объектов, создание копии Дон'т имеет особого смысла, поскольку они не собираются менять. Для изменяемых объектов assignment
,copy
и deepcopy
ведет себя по-разному. Давайте поговорим о каждой из них с примерами.
Операция присваивания просто назначает ссылка из источника к месту назначения е.г:
>>> i = [1,2,3]
>>> j=i
>>> hex(id(i)), hex(id(j))
>>> ('0x10296f908', '0x10296f908') #Both addresses are identical
Теперь я
и J
технически относится к одном списке. Как I
и J
есть же адрес памяти. Любые обновления или
из них отразится на других. е.г:
>>> i.append(4)
>>> j
>>> [1,2,3,4] #Destination is updated
>>> j.append(5)
>>> i
>>> [1,2,3,4,5] #Source is updated
С другой стороны копировать
и deepcopy
создает новый экземпляр переменной. Так что теперь изменения в исходной переменной не будут отражены
к переменной экземпляра, и наоборот. Однако копия(поверхностное копирование)`, Дон't создает копию вложенные объекты, а не просто
копирование ссылки на вложенные объекты. Deepcopy копирует все вложенные объекты рекурсивно.
Некоторые примеры, чтобы продемонстрировать поведение копировать
и deepcopy
:
Плоский пример списка с помощью "копировать":
>>> import copy
>>> i = [1,2,3]
>>> j = copy.copy(i)
>>> hex(id(i)), hex(id(j))
>>> ('0x102b9b7c8', '0x102971cc8') #Both addresses are different
>>> i.append(4)
>>> j
>>> [1,2,3] #Updation of original list didn't affected copied variable
Пример вложенного списка, используя "копировать":
>>> import copy
>>> i = [1,2,3,[4,5]]
>>> j = copy.copy(i)
>>> hex(id(i)), hex(id(j))
>>> ('0x102b9b7c8', '0x102971cc8') #Both addresses are still different
>>> hex(id(i[3])), hex(id(j[3]))
>>> ('0x10296f908', '0x10296f908') #Nested lists have same address
>>> i[3].append(6)
>>> j
>>> [1,2,3,[4,5,6]] #Updation of original nested list updated the copy as well
Плоский пример списка с помощью deepcopy
:
>>> import copy
>>> i = [1,2,3]
>>> j = copy.deepcopy(i)
>>> hex(id(i)), hex(id(j))
>>> ('0x102b9b7c8', '0x102971cc8') #Both addresses are different
>>> i.append(4)
>>> j
>>> [1,2,3] #Updation of original list didn't affected copied variable
Вложенный список пример использования deepcopy
:
>>> import copy
>>> i = [1,2,3,[4,5]]
>>> j = copy.deepcopy(i)
>>> hex(id(i)), hex(id(j))
>>> ('0x102b9b7c8', '0x102971cc8') #Both addresses are still different
>>> hex(id(i[3])), hex(id(j[3]))
>>> ('0x10296f908', '0x102b9b7c8') #Nested lists have different addresses
>>> i[3].append(6)
>>> j
>>> [1,2,3,[4,5]] #Updation of original nested list didn't affected the copied variable
Позвольте's см. В графическом примере, как следующий код выполняется:
import copy
class Foo(object):
def __init__(self):
pass
a = [Foo(), Foo()]
shallow = copy.copy(a)
deep = copy.deepcopy(a)
А, B, С, D, А1, В1, С1 и D1 являются ссылки на объекты в памяти, которые однозначно идентифицируются по их ID.
Назначение операции принимает ссылку на объект в памяти и присваивает ссылку на новое имя. с=[1,2,3,4] - это задание, которое создает новый список объектов, содержащих эти четыре числа и присваивает ссылку на этот объект до
c.
С1=C- это уступки, которые *та же ссылка на один и тот же объект* и назначает, что
С1. Поскольку список, является изменяемым, все, что происходит в этот список, будут видны независимо от того, вы получаете доступ к ней через
Cили
С1`, потому что они оба ссылаются на один объект.
С1=копия.копии(с) - это на "копию", что создает новый список и присваивает ссылку на новый список
С1.
Спо-прежнему указывает на исходный список. Так что, если вы измените список В
С1`, списке что " с " означает не изменится.
Концепция копирования не имеет значения на неизменяемые объекты, такие как целые числа и строки. Так как вы можете'т изменение этих объектов, не нужно иметь две копии одного значения в памяти по разным адресам. Итак, целых чисел и строк, и некоторые другие объекты, к которым понятие копирования не относится, просто переназначили. Поэтому ваши примеры с A
и Б результате
в одинаковых идентификаторов.
`С1=копия.deepcopy(с) - это "и глубокая копия", но он работает так же, как мелкую копию в этом примере. Глубокие копии отличаются от мелких экземпляров в этой мелкой копии сделают новую копию самого объекта, но никаких ссылок внутри этого объекта сами по себе не копируются. В вашем примере, ваш список имеет только целые числа внутри него (которые неизменны), и как говорилось ранее нет необходимости копировать их. Так что "глубоко" в части глубокое копирование не применяется. Однако, рассмотрим подробнее этот сложный список:
Е = [[1, 2],[4, 5, 6],[7, 8, 9]]`
Это список, который содержит другие списки (также можно описать как двумерный массив).
Если вы запустите на "копию" О Е
, скопировав его в "Е1", вы увидите, что идентификатор список изменений, но каждая копия содержит список ссылок на те же три списки -- списки с числами внутри. Это означает, что если вы должны были сделать е[0].добавить(3)
, то е
будет[[1, 2, 3],[4, 5, 6],[7, 8, 9]]
. Но " Е1 " будут[[1, 2, 3],[4, 5, 6],[7, 8, 9]]
. С другой стороны, если вы впоследствии сделал е.добавить([10, 11, 12]),
е будет[[1, 2, 3],[4, 5, 6],[7, 8, 9],[10, 11, 12]]
. Но " Е1 " до сих пор бы[[1, 2, 3],[4, 5, 6],[7, 8, 9]]
. Что's, потому что внешние списки представляют собой отдельные объекты, которые изначально содержат три ссылки на три внутренние списки. Если вам модифицировать список, вы можете увидеть эти изменения, независимо от того, если Вы читаете их через одну копию или другую. Но если вы измените одну из внешних списков, как указано выше, а затем " Е " содержит три ссылки на оригинал три списка плюс еще одна ссылка на новый список. И " Е1 " по-прежнему содержит только оригинальный три ссылки.
Это 'глубокая копия' не только дублировать внешний список, но также побывать внутри списков и дублировать внутренними списками, так что две результирующие объекты не содержат ни одной ссылки (насколько изменяемые объекты беспокоит). Если внутренний список еще списки (или другие объекты, такие как словари) внутри них, они тоже будут повторяться. Что'ы 'глубокая' часть 'глубокая копия'.
В Python, когда мы приписываем такие объекты, как списки, кортежи, дикт и т. д. На другой объект, как правило, с ' = ' знак, питон создает копии ссылка. То есть, допустим, у нас есть список вроде этого :
list1 = [ [ 'a' , 'b' , 'c' ] , [ 'd' , 'e' , 'f' ] ]
и мы назначаем еще один список в этот список, как :
list2 = list1
тогда, если мы печатаем список2 в Python терминал мы получим это :
list2 = [ [ 'a', 'b', 'c'] , [ 'd', 'e', ' f '] ]
Как список1 & список2 указывая в то же место памяти, любое изменение любого из них приведет к заметным изменениям в оба объекта, я.е оба объекта указывают на то же место в памяти. Если мы изменим список1 такой :
list1[0][0] = 'x’
list1.append( [ 'g'] )
тогда как список1 и список2 будет :
list1 = [ [ 'x', 'b', 'c'] , [ 'd', 'e', ' f '] , [ 'g'] ]
list2 = [ [ 'x', 'b', 'c'] , [ 'd', 'e', ' f '] , [ 'g’ ] ]
Сейчас подходит к поверхностное копирование, когда два объекты копируются через мелкую копию, дочерний объект как родительский объект относится к той же области памяти, но любые дальнейшие изменения в скопированный объект будет независим друг от друга. Давайте разберемся в этом на маленьком примере. Предположим, у нас есть этот небольшой фрагмент кода :
import copy
list1 = [ [ 'a', 'b', 'c'] , [ 'd', 'e', ' f '] ] # assigning a list
list2 = copy.copy(list1) # shallow copy is done using copy function of copy module
list1.append ( [ 'g', 'h', 'i'] ) # appending another list to list1
print list1
list1 = [ [ 'a', 'b', 'c'] , [ 'd', 'e', ' f '] , [ 'g', 'h', 'i'] ]
list2 = [ [ 'a', 'b', 'c'] , [ 'd', 'e', ' f '] ]
обратите внимание, список2 остается в силе, но если мы вносим изменения в дочерние объекты, как :
list1[0][0] = 'x’
тогда как список1 и список2 будет меняться :
list1 = [ [ 'x', 'b', 'c'] , [ 'd', 'e', ' f '] , [ 'g', 'h', 'i'] ]
list2 = [ [ 'x', 'b', 'c'] , [ 'd', 'e', ' f '] ]
Теперь, глубокая копия способствует формированию полностью изолированных объектов друг из друга. Если два объекта будут скопированы через глубокую копию, то оба родителя & это ребенок будет указывать на другую область памяти. Пример :
import copy
list1 = [ [ 'a', 'b', 'c'] , [ 'd', 'e', ' f '] ] # assigning a list
list2 = deepcopy.copy(list1) # deep copy is done using deepcopy function of copy module
list1.append ( [ 'g', 'h', 'i'] ) # appending another list to list1
print list1
list1 = [ [ 'a', 'b', 'c'] , [ 'd', 'e', ' f '] , [ 'g', 'h', 'i'] ]
list2 = [ [ 'a', 'b', 'c'] , [ 'd', 'e', ' f '] ]
обратите внимание, список2 остается в силе, но если мы вносим изменения в дочерние объекты, как :
list1[0][0] = 'x’
затем также список2 будет в силе, как и все дочерние объекты родительского объекта и указывает на другую область памяти :
list1 = [ [ 'x', 'b', 'c'] , [ 'd', 'e', ' f '] , [ 'g', 'h', 'i'] ]
list2 = [ [ 'a', 'b', 'c'] , [ 'd', 'e', ' f ' ] ]
Надеюсь, что это помогает.
Не уверен, если это указано выше или нет, но это's очень импортируемые, чтобы понять, что .копия() создайте ссылку на исходный объект. Если вы измените скопированный объект - изменить исходный объект. .deepcopy() создает новый объект и делает реальные копирования исходного объекта в новый. Изменения новый объект deepcopied не'т повлиять на исходный объект.
И да .deepcopy() копирует исходный объект рекурсивно, пока .копия() создать ссылку на объект первого уровня-данные исходного объекта.
Поэтому копирование/ссылающиеся разница между .копия() и .deepcopy() является значительным.
Код ниже демонстрирует разницу между назначениями, мелкую копию, используя метод копирования, мелкую копию, используя (фрагмент) [:] и deepcopy. Ниже пример использует вложенные списки есть, сделав различия более очевидны.
from copy import deepcopy
########"List assignment (does not create a copy) ############
l1 = [1,2,3, [4,5,6], [7,8,9]]
l1_assigned = l1
print(l1)
print(l1_assigned)
print(id(l1), id(l1_assigned))
print(id(l1[3]), id(l1_assigned[3]))
print(id(l1[3][0]), id(l1_assigned[3][0]))
l1[3][0] = 100
l1.pop(4)
l1.remove(1)
print(l1)
print(l1_assigned)
print("###################################")
########"List copy using copy method (shallow copy)############
l2 = [1,2,3, [4,5,6], [7,8,9]]
l2_copy = l2.copy()
print(l2)
print(l2_copy)
print(id(l2), id(l2_copy))
print(id(l2[3]), id(l2_copy[3]))
print(id(l2[3][0]), id(l2_copy[3][0]))
l2[3][0] = 100
l2.pop(4)
l2.remove(1)
print(l2)
print(l2_copy)
print("###################################")
########"List copy using slice (shallow copy)############
l3 = [1,2,3, [4,5,6], [7,8,9]]
l3_slice = l3[:]
print(l3)
print(l3_slice)
print(id(l3), id(l3_slice))
print(id(l3[3]), id(l3_slice[3]))
print(id(l3[3][0]), id(l3_slice[3][0]))
l3[3][0] = 100
l3.pop(4)
l3.remove(1)
print(l3)
print(l3_slice)
print("###################################")
########"List copy using deepcopy ############
l4 = [1,2,3, [4,5,6], [7,8,9]]
l4_deep = deepcopy(l4)
print(l4)
print(l4_deep)
print(id(l4), id(l4_deep))
print(id(l4[3]), id(l4_deep[3]))
print(id(l4[3][0]), id(l4_deep[3][0]))
l4[3][0] = 100
l4.pop(4)
l4.remove(1)
print(l4)
print(l4_deep)
print("##########################")
print(l4[2], id(l4[2]))
print(l4_deep[3], id(l4_deep[3]))
print(l4[2][0], id(l4[2][0]))
print(l4_deep[3][0], id(l4_deep[3][0]))
Суть состоит в этом:
Дело с мелкой списки (не sub_lists, только отдельные элементы), используя "и обычное назначение на" поднимается на "побочный эффект" при создании неглубоких список, а затем создать копию этого списка, используя "и обычное назначение и". Этот фильм "побочный эффект" это когда вы изменить любой элемент из списка копирования, потому что он автоматически изменит одинаковые элементы исходного списка. То есть, когда копия
пригождается, так как он выиграл'т изменение исходных элементов списка при изменении элементов копирования.
С другой стороны, "копировать" есть и "побочный эффект" и как хорошо, когда у вас есть список, что есть списки в нем (sub_lists) и deepcopy решает он. Например, если вы создаете большой список, который содержит вложенные списки в нем (sub_lists) и создайте копию этого большого списка (первоначальный список). В "побочный эффект", которая может возникнуть при изменении sub_lists списка экземпляре, который будет автоматически изменять sub_lists большой список. Иногда (в некоторых проектах), что вы хотите сохранить большой список (ваш первоначальный список) как это без изменений, и все, что вы хотите, чтобы скопировать его элементы (sub_lists). Для этого, ваше решение использовать deepcopy`, который будет заботиться об этом, что "побочный эффект" и делает копию без изменения первоначального содержания.
Поведении различных копировать
и операций глубокую копию
касается только составные объекты (т. е. объекты, которые содержат другие объекты, такие как списки).
Вот отличия показано в этом простом примере кода:
Первая
позвольте's проверьте как копия
(мелкой) ведет себя, создавая оригинальный список и копию этого списка:
import copy
original_list = [1, 2, 3, 4, 5, ['a', 'b']]
copy_list = copy.copy(original_list)
Теперь, позвольте's запускает тесты некоторых "печать" и увидеть, как первоначальный список ведут себя по сравнению с его копировать список:
original_list и copy_list имеют разные адреса
print(hex(id(original_list)), hex(id(copy_list))) # 0x1fb3030 0x1fb3328
элементы original_list и copy_list имеют одинаковые адреса
print(hex(id(original_list[1])), hex(id(copy_list[1]))) # 0x537ed440 0x537ed440
sub_elements из original_list и copy_list имеют одинаковые адреса
print(hex(id(original_list[5])), hex(id(copy_list[5]))) # 0x1faef08 0x1faef08
изменение элементов original_list не изменяет элементы copy_list
original_list.append(6)
print("original_list is:", original_list) # original_list is: [1, 2, 3, 4, 5, ['a', 'b'], 6]
print("copy_list is:", copy_list) # copy_list is: [1, 2, 3, 4, 5, ['a', 'b']]
изменение элементов copy_list не изменяет элементы original_list
copy_list.append(7)
print("original_list is:", original_list) # original_list is: [1, 2, 3, 4, 5, ['a', 'b'], 6]
print("copy_list is:", copy_list) # copy_list is: [1, 2, 3, 4, 5, ['a', 'b'], 7]
изменение sub_elements original_list автоматически изменять sub_elements copy_list
original_list[5].append('c')
print("original_list is:", original_list) # original_list is: [1, 2, 3, 4, 5, ['a', 'b', 'c'], 6]
print("copy_list is:", copy_list) # copy_list is: [1, 2, 3, 4, 5, ['a', 'b', 'c'], 7]
изменение sub_elements copy_list автоматически изменять sub_elements original_list
copy_list[5].append('d')
print("original_list is:", original_list) # original_list is: [1, 2, 3, 4, 5, ['a', 'b', 'c', 'd'], 6]
print("copy_list is:", copy_list) # copy_list is: [1, 2, 3, 4, 5, ['a', 'b', 'c', 'd'], 7]
Второй
позвольте's проверьте как deepcopy` ведет себя, делая то же самое, как мы сделали с "копировать" (создание оригинального списка и копию этого списка):
import copy
original_list = [1, 2, 3, 4, 5, ['a', 'b']]
copy_list = copy.copy(original_list)
Теперь, позвольте's запускает тесты некоторых "печать" и увидеть, как первоначальный список ведут себя по сравнению с его копировать список:
import copy
original_list = [1, 2, 3, 4, 5, ['a', 'b']]
copy_list = copy.deepcopy(original_list)
original_list и copy_list имеют разные адреса
print(hex(id(original_list)), hex(id(copy_list))) # 0x1fb3030 0x1fb3328
элементы original_list и copy_list имеют одинаковые адреса
print(hex(id(original_list[1])), hex(id(copy_list[1]))) # 0x537ed440 0x537ed440
sub_elements из original_list и copy_list имеют разные адреса
print(hex(id(original_list[5])), hex(id(copy_list[5]))) # 0x24eef08 0x24f3300
изменение элементов original_list не изменяет элементы copy_list
original_list.append(6)
print("original_list is:", original_list) # original_list is: [1, 2, 3, 4, 5, ['a', 'b'], 6]
print("copy_list is:", copy_list) # copy_list is: [1, 2, 3, 4, 5, ['a', 'b']]
изменение элементов copy_list не изменяет элементы original_list
copy_list.append(7)
print("original_list is:", original_list) # original_list is: [1, 2, 3, 4, 5, ['a', 'b'], 6]
print("copy_list is:", copy_list) # copy_list is: [1, 2, 3, 4, 5, ['a', 'b'], 7]
изменение sub_elements original_list не изменяет sub_elements copy_list
original_list[5].append('c')
print("original_list is:", original_list) # original_list is: [1, 2, 3, 4, 5, ['a', 'b', 'c'], 6]
print("copy_list is:", copy_list) # copy_list is: [1, 2, 3, 4, 5, ['a', 'b'], 7]
изменение sub_elements copy_list не изменяет sub_elements original_list
copy_list[5].append('d')
print("original_list is:", original_list) # original_list is: [1, 2, 3, 4, 5, ['a', 'b', 'c', 'd'], 6]
print("copy_list is:", copy_list) # copy_list is: [1, 2, 3, 4, 5, ['a', 'b', 'd'], 7]
>>lst=[1,2,3,4,5]
>>a=lst
>>b=lst[:]
>>> b
[1, 2, 3, 4, 5]
>>> a
[1, 2, 3, 4, 5]
>>> lst is b
False
>>> lst is a
True
>>> id(lst)
46263192
>>> id(a)
46263192 ------> See here id of a and id of lst is same so its called deep copy and even boolean answer is true
>>> id(b)
46263512 ------> See here id of b and id of lst is not same so its called shallow copy and even boolean answer is false although output looks same.