В чем разница между мелким копированием, глубокой копией и обычной операцией назначения?

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

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

Ответы на вопрос(9)

Посмотрите в графическом примере, как выполняется следующий код:

import copy

class Foo(object):
    def __init__(self):
        pass


a = [Foo(), Foo()]
shallow = copy.copy(a)
deep = copy.deepcopy(a)

поскольку данные никогда не изменятся, поэтому Python использует те же данные; идентификаторы всегда одинаковы. Для изменчивых объектов, поскольку они могут потенциально изменяться, [мелкая] копия создает новый объект.

Глубокая копия связана с вложенными структурами. Если у вас есть список списков, то Deepcopycopies вложенные списки также, так что это рекурсивная копия. С помощью просто копирования у вас есть новый внешний список, но внутренние списки являются ссылками.

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

 Alston12 нояб. 2016 г., 09:35
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 остается тем же, так что внутренний список является ссылками?
 perreal12 нояб. 2016 г., 18:07
@ Stallman Вы не меняете ссылочный список здесь, просто создаете новый список и назначаете его в качестве первого элемента одной из копий. попробуй сделатьlist_[0][0] = 7

поверхностным копированием с использованием метода копирования, поверхностным копированием с использованием (среза) [:] и глубокой копией. Приведенный ниже пример использует вложенные списки, делая различия более очевидными.

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]))

когда мы присваиваем такие объекты, как list, tuple, dict и т. Д. Другому объекту, обычно с помощью «=» знак, Python создает копиипо ссылке, То есть, давайтескажем, у нас есть список списка, как это:

list1 = [ [ 'a' , 'b' , 'c' ] , [ 'd' , 'e' , 'f' ]  ]

и мы назначаем другой список этому списку, как:

list2 = list1

тогда, если мы печатаем list2 в терминале Python, мыЯ получу это:

list2 = [ [ 'a', 'b', 'c'] , [ 'd', 'e', ' f ']  ]

Оба list1 & list2 указывают на одну и ту же область памяти, любое изменение любого из них приведет к изменениям, видимым в обоих объектах, т.е. оба объекта указывают на одну и ту же область памяти. Если мы изменим list1 следующим образом:

list1[0][0] = 'x’
list1.append( [ 'g'] )

тогда и list1, и list2 будут:

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 '] ]

обратите внимание, list2 остается неизменным, но если мы внесем изменения в дочерние объекты, такие как:

list1[0][0] = 'x’

тогда и list1, и list2 получат изменения:

list1 = [ [ 'x', 'b', 'c'] , [ 'd', 'e', ' f '] , [ 'g', 'h', 'i'] ] 
list2 = [ [ 'x', 'b', 'c'] , [ 'd', 'e', ' f '] ]

Сейчас,Глубокая копия помогает в создании полностью изолированных объектов друг от друга. Если два объекта копируются с помощью Deep Copy, то оба родительских и Это's ребенок будет указывать на другую область памяти. Пример :

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 '] ]

обратите внимание, list2 остается неизменным, но если мы внесем изменения в дочерние объекты, такие как:

list1[0][0] = 'x’

тогда list2 не будет затронут, так как все дочерние объекты и родительские объекты указывают на другое место в памяти:

list1 = [ [ 'x', 'b', 'c'] , [ 'd', 'e', ' f '] , [ 'g', 'h', 'i'] ] 
list2 = [ [ 'a', 'b', 'c'] , [ 'd', 'e', ' f  ' ] ]

Надеюсь, поможет.

Решение Вопроса

вующий объект.документы объясните разницу между мелкими и глубокими копиями:

Разница между мелким и глубоким копированием относится только к составным объектам (объектам, которые содержат другие объекты, такие как списки или экземпляры классов):

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

Глубокая копия создает новый составной объект, а затем рекурсивно вставляет в него копии объектов, найденных в оригинале.

Вот'Небольшая демонстрация:

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
 grc12 нояб. 2016 г., 10:06
@ Stallman Если вы копируетесоединение объект, содержащий изменяемые объекты, то изменяемые объекты существуют только один раз. Все изменения в изменяемых объектах будут отражены как в исходном составном объекте, так и в скопированном составном объекте.
 Neerav07 мая 2014 г., 02:03
@grc "Любые изменения в существующем объекте будут влиять на обе переменные (с присваиванием) - это утверждение верно только для изменяемых объектов и не неизменяемых типов, таких как string, float, tuples.
 Alston12 нояб. 2016 г., 13:22
@grc Ой, что я делаю, чтобы изменить ссылку на другой список[7,8], но реальная модификация должна изменить элемент по адресуlist_[0], Это мнение правильно?
 Alston12 нояб. 2016 г., 09:28
@grcA shallow copy constructs a new compound object and then (to the extent possible) inserts references into it to the objects found in the original. Вы имеете в виду, что, поскольку я делаю поверхностное копирование в изменяемый объект, новый объект может зависеть от исходного скопированного?
 grc22 июн. 2013 г., 04:33
@Dshank Нет. Мелкая копия создает новый объект, в то время как присвоение просто укажет новую переменную на существующий объект. Любые изменения в существующем объекте будут влиять на обе переменные (с присваиванием).
 grc12 нояб. 2016 г., 10:58
@Stallmanlist_[0] изменчив, но вы не изменяете / не изменяете его. Пытатьсяlist_[0].append(9) или жеlist_[0][0] = 7 вместо.
 grc12 нояб. 2016 г., 15:02
@ Stallman да, это звучит правильно.
 Alston12 нояб. 2016 г., 10:18
@grc Но я попробовал пример (я удаляю новую строку здесь.)list_=[[1,2],[3,4]] newlist = list_.copy() list_[0]=[7,8] print(list_) print(newlist) newlist по-прежнему отображать[[1, 2], [3, 4]], Ноlist_[0] это список, который является изменчивым.
 Lee8809 мар. 2017 г., 14:38
@grc Это было очень полезное обсуждение, но у меня есть больше "философский» вопрос. Я думаю, что было бы справедливо сказать, что большинство начинающих программистов интуитивно ожидают глубокого копирования. Не могли бы вы пролить свет на то, почему мелкое копирование имеет значение? В какой ситуации мы бы не хотели глубоких копий? (И простите меня, если мое предположение о том, что большинство людей хотят глубокого копирования, ошибочно)
 deeshank22 июн. 2013 г., 04:31
такое назначение такое же как мелкая копия?

создание копии нене имеет большого смысла, так как они не собираются меняться. Для изменяемых объектовassignmentcopy а такжеdeepcopy ведет себя по-разному. Давайте поговорим о каждом из них с примерами.

Операция присваивания просто назначает ссылку источника на место назначения, например:

>>> i = [1,2,3]
>>> j=i
>>> hex(id(i)), hex(id(j))
>>> ('0x10296f908', '0x10296f908') #Both addresses are identical

Сейчасi а также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

С другой стороныcopy а такжеdeepcopy создает новую копию переменной. Так что теперь изменения в исходной переменной не будут отражены в переменной копирования и наоборот. тем не мениеcopy(shallow copy)не надоt создает копию вложенных объектов, вместо этого он просто копирует ссылку на вложенные объекты. Deepcopy рекурсивно копирует все вложенные объекты.

Некоторые примеры, демонстрирующие поведениеcopy а также :deepcopy

Пример плоского списка с использованием:copy

>>> 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

Пример вложенного списка с использованием:copy

>>> 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    

Работа с неглубокими списками (без вложенных списков, только отдельные элементы), используя "нормальное назначение поднимаетсяпобочный эффект" когда вы создаете мелкий список, а затем вы создаете копию этого списка с помощью "нормальное назначение, Это "побочный эффект" это когда вы изменяете любой элемент созданного списка копий, потому что он автоматически изменит те же элементы исходного списка. Это когдаcopy пригодится, так как выигралt изменять исходные элементы списка при изменении копируемых элементов.

С другой стороны,copy есть "побочный эффект" также, когда у вас есть список, в котором есть списки (sub_lists), иdeepcopy решает это. Например, если вы создаете большой список, в котором есть вложенные списки (sub_lists), и вы создаете копию этого большого списка (исходный список). "побочный эффект" возникнет при изменении подсписков списка копирования, которые автоматически изменят подсписки большого списка. Иногда (в некоторых проектах) вы хотите сохранить большой список (ваш оригинальный список) без изменений, и все, что вам нужно, - это сделать копию его элементов (sub_lists). Для этого ваше решение заключается в использованииdeepcopy который позаботится об этом "побочный эффект" и делает копию без изменения исходного содержимого.

Различное поведениеcopy а такжеdeep copy операции относятся только к составным объектам (т. е. объектам, которые содержат другие объекты, такие как списки).

Вот различия, показанные в этом простом примере кода:

Первый

позволять'проверить какcopy (мелкий) ведет себя, создавая оригинальный список и копию этого списка:

import copy
original_list = [1, 2, 3, 4, 5, ['a', 'b']]
copy_list = copy.copy(original_list)

Теперь давайтеs запустить некоторыеprint тестирует и видит, как ведет себя оригинальный список по сравнению со списком копий:

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 of 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]

второй

позволять'проверить какdeepcopy ведет себя, делая то же самое, что мы сделали сcopy (создание оригинального списка и копии этого списка):

import copy
original_list = [1, 2, 3, 4, 5, ['a', 'b']]
copy_list = copy.copy(original_list)

Теперь давайтеs запустить некоторыеprint тестирует и видит, как ведет себя оригинальный список по сравнению со списком копий:

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]

модификация original_list sub_elements НЕ изменяет copy_list sub_elements

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]

изменение copy_list sub_elements НЕ изменяет original_list sub_elements

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]

b, c, d, 1, b1, c1 и d1 являются ссылками на объекты в памяти, которые однозначно идентифицируются по их идентификаторам.

Операция присваивания берет ссылку на объект в памяти и присваивает эту ссылку новому имени.c=[1,2,3,4] это назначение, которое создает новый объект списка, содержащий эти четыре целых числа, и назначает ссылку на этот объект.cc1=c это задание, которое занимаетта же ссылка на тот же объект и назначает этоc1, Поскольку список является изменяемым, все, что происходит с этим списком, будет видно независимо от того, обращаетесь ли вы к нему черезc или жеc1потому что они оба ссылаются на один и тот же объект.

c1=copy.copy(c) это "мелкая копия " это создает новый список и назначает ссылку на новый список.c1c по-прежнему указывает на исходный список. Итак, если вы измените список вc1, список, которыйc относится к не изменится.

Концепция копирования не имеет отношения к неизменным объектам, таким как целые числа и строки. Так как вы можетеДля изменения этих объектов никогда не нужно иметь две копии одного и того же значения в памяти в разных местах. Таким образом, целые числа и строки, а также некоторые другие объекты, к которым концепция копирования не применяется, просто переназначаются. Вот почему ваши примеры с а такжеb результат в идентичных идентификаторах.

c1=copy.deepcopy(c) это "глубокая копия ", но он функционирует так же, как мелкая копия в этом примере. Глубокие копии отличаются от мелких копий тем, что мелкие копии будут создавать новую копию самого объекта, но любые ссылкивнутри этот объект не будет скопирован. В вашем примере ваш список содержит только целые числа (которые являются неизменяемыми), и, как обсуждалось ранее, их не нужно копировать. Итак "глубокий» часть глубокой копии не распространяется. Однако рассмотрим этот более сложный список:

e = [[1, 2],[4, 5, 6],[7, 8, 9]]

Это список, который содержит другие списки (вы также можете описать его как двумерный массив).

Если вы запускаетемелкая копия " наe, копируя его вe1, вы обнаружите, что идентификатор списка меняется, но каждая копия списка содержит ссылки на те же три списка - списки с целыми числами внутри. Это означает, что если вы должны были сделатьe[0].ppend(3), затемe было бы[[1, 2, 3],[4, 5, 6],[7, 8, 9]], Ноe1 также будет[[1, 2, 3],[4, 5, 6],[7, 8, 9]], С другой стороны, если вы впоследствии сделали,e.ppend([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 до сих пор содержит только три исходные ссылки.

глубокая копия будет не только дублировать внешний список, но также будет входить в списки и дублировать внутренние списки, чтобы два результирующих объекта не содержали ни одной из одинаковых ссылок (в том, что касается изменяемых объектов). Если бы у внутренних списков были дополнительные списки (или другие объекты, такие как словари) внутри них, они тоже были бы дублированы. Тот'сглубокий» часть 'глубокая копия ».

>>lst=[1,2,3,4,5]

б = LST [:]

б [1, 2, 3, 4, 5]

[1, 2, 3, 4, 5]

Это ложно

Это Истина

id (lst) 46263192

id (a) 46263192 ------> Смотрите здесь, идентификатор a и id lst одинаковы, поэтому его так называемая глубокая копия и даже логический ответ верны

id (b) 46263512 ------> Смотрите здесь id b и id lst не одно и то же, поэтому его называют мелкой копией, и даже логический ответ - false, хотя вывод выглядит одинаково.

Ваш ответ на вопрос