Qual é a diferença entre cópia superficial, cópia em profundidade e operação de atribuição normal?

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

Eu recebo os seguintes resultados:

immutable - id(a)==id(a1) True
immutable - id(b)==id(b1) True
mutable - id(c)==id(c1) False
mutable - id(d)==id(d1) False

Se eu fizer uma cópia em profundidade:

a1 = copy.deepcopy(a)
b1 = copy.deepcopy(b)
c1 = copy.deepcopy(c)
d1 = copy.deepcopy(d)

os resultados são os mesmos:

immutable - id(a)==id(a1) True
immutable - id(b)==id(b1) True
mutable - id(c)==id(c1) False
mutable - id(d)==id(d1) False

Se eu trabalhar em operações de atribuição:

a1 = a
b1 = b
c1 = c
d1 = d

então os resultados são:

immutable - id(a)==id(a1) True
immutable - id(b)==id(b1) True
mutable - id(c)==id(c1) True
mutable - id(d)==id(d1) True

Alguém pode explicar o que exatamente faz a diferença entre as cópias? É algo relacionado a objetos mutáveis ​​e imutáveis? Se sim, você pode me explicar?

deeshank
fonte

Respostas:

364

As operações normais de atribuição apontarão a nova variável para o objeto existente. Os documentos explicam a diferença entre cópias rasas e profundas:

A diferença entre cópia superficial e profunda é relevante apenas para objetos compostos (objetos que contêm outros objetos, como listas ou instâncias de classe):

  • Uma cópia superficial constrói um novo objeto composto e, em seguida, (na medida do possível) insere referências aos objetos encontrados no original.

  • Uma cópia profunda constrói um novo objeto composto e, em seguida, recursivamente, insere cópias dos objetos encontrados no original.

Aqui está uma pequena demonstração:

import copy

a = [1, 2, 3]
b = [4, 5, 6]
c = [a, b]

Usando operações normais de atribuição para copiar:

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]

Usando uma cópia superficial:

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]

Usando uma cópia profunda:

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
grc
fonte
5
a atribuição é igual à cópia superficial?
deeshank
35
@Dshank No. Uma cópia superficial constrói um novo objeto, enquanto uma atribuição simplesmente aponta a nova variável para o objeto existente. Quaisquer alterações no objeto existente afetarão as duas variáveis ​​(com atribuição).
grc 22/06
13
@grc "Quaisquer alterações no objeto existente afetarão ambas as variáveis ​​(com atribuição)" - esta afirmação é verdadeira apenas para objetos mutáveis ​​e não para tipos imutáveis, como string, float, tuples.
Neerav
1
@grc Mas eu tentei um exemplo (removo a nova linha aqui.) list_=[[1,2],[3,4]] newlist = list_.copy() list_[0]=[7,8] print(list_) print(newlist)A newlistexibição continua [[1, 2], [3, 4]]. Mas list_[0]é uma lista que é mutável.
Alston
1
O @Stallman list_[0]é mutável, mas você não o está modificando / modificando. Tente list_[0].append(9)ou em list_[0][0] = 7vez disso.
grc 12/11
46

Para objetos imutáveis, não há necessidade de copiar porque os dados nunca mudam; portanto, o Python usa os mesmos dados; ids são sempre os mesmos. Para objetos mutáveis, como eles podem mudar potencialmente, a cópia [superficial] cria um novo objeto.

A cópia profunda está relacionada a estruturas aninhadas. Se você tiver uma lista de listas, copie copiestambém as listas aninhadas, para que seja uma cópia recursiva. Com apenas copiar, você tem uma nova lista externa, mas listas internas são referências.

A atribuição não copia. Simplesmente define a referência para os dados antigos. Então você precisa copiar para criar uma nova lista com o mesmo conteúdo.

perreal
fonte
With just copy, you have a new outer list but inner lists are references.Para as listas internas, a copiada seria influenciada pela original? Eu crio uma lista de listas como list_=[[1,2],[3,4]] newlist = list_.copy() list_[0]=[7,8]e newlistas mesmas permanecem, a lista interna é referência?
Alston
1
@Stallman, você não está alterando a lista referenciada aqui, apenas criando uma nova lista e atribuindo-a como o primeiro item de uma das cópias. tente fazerlist_[0][0] = 7
perreal
20

Para objetos imutáveis, criar uma cópia não faz muito sentido, pois eles não vão mudar. Para objetos mutáveis assignment, copyedeepcopy comporta-se diferentemente. Vamos falar sobre cada um deles com exemplos.

Uma operação de atribuição simplesmente atribui a referência da fonte ao destino, por exemplo:

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

Agora ie jtecnicamente se refere à mesma lista. Ambos ie jtêm o mesmo endereço de memória. Qualquer atualização para um deles será refletida no outro. por exemplo:

>>> i.append(4)
>>> j
>>> [1,2,3,4] #Destination is updated

>>> j.append(5)
>>> i
>>> [1,2,3,4,5] #Source is updated

Por outro lado copye deepcopycria uma nova cópia da variável. Portanto, agora as alterações na variável original não serão refletidas na variável de cópia e vice-versa. Contudocopy(shallow copy) , não cria uma cópia de objetos aninhados, apenas copia a referência de objetos aninhados. A cópia em profundidade copia todos os objetos aninhados recursivamente.

Alguns exemplos para demonstrar o comportamento copyedeepcopy :

Exemplo de lista simples usando 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

Exemplo de lista aninhada usando 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

Exemplo de lista simples usando 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

Exemplo de lista aninhada usando 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    
Sohaib Farooqi
fonte
18

Vamos ver em um exemplo gráfico como o seguinte código é executado:

import copy

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


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

insira a descrição da imagem aqui

user1767754
fonte
5

a, b, c, d, a1, b1, c1 e d1 são referências a objetos na memória, identificados exclusivamente por seus IDs.

Uma operação de atribuição faz uma referência ao objeto na memória e atribui essa referência a um novo nome. c=[1,2,3,4]é uma atribuição que cria um novo objeto de lista que contém esses quatro números inteiros e atribui a referência a esse objeto c. c1=cé uma atribuição que leva a mesma referência ao mesmo objeto e a atribui a isso c1. Como a lista é mutável, tudo o que acontecer com essa lista ficará visível, independentemente de você ser acessado através couc1 , porque ambos fazem referência ao mesmo objeto.

c1=copy.copy(c)é uma "cópia superficial" que cria uma nova lista e atribui a referência à nova lista c1. cainda aponta para a lista original. Portanto, se você modificar a lista em c1, a lista quec se refere não será alterada.

O conceito de cópia é irrelevante para objetos imutáveis, como números inteiros e seqüências de caracteres. Como você não pode modificar esses objetos, nunca é necessário ter duas cópias do mesmo valor na memória em locais diferentes. Portanto, números inteiros e seqüências de caracteres, e alguns outros objetos aos quais o conceito de cópia não se aplica, são simplesmente reatribuídos. É por isso que seus exemplos ae bresultam em IDs idênticos.

c1=copy.deepcopy(c)é uma "cópia profunda", mas funciona da mesma forma que uma cópia superficial neste exemplo. As cópias profundas diferem das cópias rasas, pois as cópias rasas criarão uma nova cópia do objeto em si, mas as referências dentro desse objeto não serão copiadas. No seu exemplo, sua lista possui apenas números inteiros (imutáveis) e, como discutido anteriormente, não há necessidade de copiá-los. Portanto, a parte "profunda" da cópia profunda não se aplica. No entanto, considere esta lista mais complexa:

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

Esta é uma lista que contém outras listas (você também pode descrevê-la como uma matriz bidimensional).

Se você executar uma "cópia superficial" e, copiando-a para e1, descobrirá que o ID da lista é alterado, mas cada cópia da lista contém referências às mesmas três listas - as listas com números inteiros. Isso significa que, se você fosse fazer e[0].append(3), eseria [[1, 2, 3],[4, 5, 6],[7, 8, 9]]. Mas e1também seria [[1, 2, 3],[4, 5, 6],[7, 8, 9]]. Por outro lado, se você fez posteriormente e.append([10, 11, 12]), eseria [[1, 2, 3],[4, 5, 6],[7, 8, 9],[10, 11, 12]]. Mas e1ainda seria [[1, 2, 3],[4, 5, 6],[7, 8, 9]]. Isso ocorre porque as listas externas são objetos separados, que inicialmente contêm três referências a três listas internas. Se você modificar as listas internas, poderá ver essas alterações, independentemente de visualizá-las através de uma cópia ou de outra. Mas se você modificar uma das listas externas como acima,e contém três referências às três listas originais e mais uma referência a uma nova lista. E e1ainda contém apenas as três referências originais.

Uma 'cópia profunda' não apenas duplicaria a lista externa, mas também entraria nas listas e duplicaria as listas internas, para que os dois objetos resultantes não contenham nenhuma das mesmas referências (no que diz respeito a objetos mutáveis) . Se as listas internas tivessem listas adicionais (ou outros objetos, como dicionários), elas também seriam duplicadas. Essa é a parte 'profunda' da 'cópia profunda'.

Andrew Gorcester
fonte
2

No python, quando atribuímos objetos como list, tuples, dict, etc a outro objeto geralmente com um sinal '=', o python cria cópias por referência . Ou seja, digamos que temos uma lista de lista como esta:

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

e atribuímos outra lista a essa lista, como:

list2 = list1

então, se imprimirmos a lista2 no terminal python, obteremos o seguinte:

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

Tanto list1 como list2 estão apontando para o mesmo local de memória, qualquer alteração em qualquer um deles resultará em alterações visíveis nos dois objetos, ou seja, os dois objetos estão apontando para o mesmo local de memória. Se mudarmos a lista1 assim:

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

então list1 e list2 serão:

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

Agora, na cópia Raso , quando dois objetos são copiados via cópia rasa, o objeto filho de ambos os objetos pai se refere ao mesmo local da memória, mas quaisquer novas alterações adicionais em qualquer objeto copiado serão independentes entre si. Vamos entender isso com um pequeno exemplo. Suponha que tenhamos esse pequeno trecho de código:

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

Observe que a lista2 permanece inalterada, mas se fizermos alterações nos objetos filho, como:

list1[0][0] = 'x’

então list1 e list2 serão alteradas:

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

Agora, a cópia profunda ajuda a criar objetos completamente isolados um do outro. Se dois objetos forem copiados via Deep Copy, o pai e o filho apontarão para um local de memória diferente. Exemplo:

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

Observe que a lista2 permanece inalterada, mas se fizermos alterações nos objetos filho, como:

list1[0][0] = 'x’

a lista2 também não será afetada, pois todos os objetos filho e objeto pai apontam para um local de memória diferente:

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

Espero que ajude.

Nitish Chauhan
fonte
0

O código abaixo demonstra a diferença entre atribuição, cópia rasa usando o método de cópia, cópia rasa usando a (fatia) [:] e a cópia em profundidade. O exemplo abaixo usa listas aninhadas, tornando as diferenças mais evidentes.

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]))
Sandeep
fonte
0

O GIST a ser adotado é o seguinte: Lidar com listas rasas (sem sub-listas, apenas elementos únicos) usando "atribuição normal" aumenta um "efeito colateral" quando você cria uma lista superficial e depois cria uma cópia dessa lista usando "atribuição normal" . Esse "efeito colateral" ocorre quando você altera qualquer elemento da lista de cópias criada, porque altera automaticamente os mesmos elementos da lista original. É quando isso é copyútil, pois não altera os elementos da lista original ao alterar os elementos de cópia.

Por outro lado, copytambém tem um "efeito colateral", quando você tem uma lista que contém listas (sub_lists) e a deepcopyresolve. Por exemplo, se você criar uma grande lista que contém listas aninhadas (sub_lists) e criar uma cópia dessa grande lista (a lista original). O "efeito colateral" surgiria quando você modificar as sub-listas da lista de cópias, que modificariam automaticamente as sub-listas da grande lista. Às vezes (em alguns projetos) você deseja manter a grande lista (sua lista original) sem modificações, e tudo o que você deseja é fazer uma cópia de seus elementos (sub_lists). Para isso, sua solução é usar o deepcopyque cuidará desse "efeito colateral" e fará uma cópia sem modificar o conteúdo original.

Os diferentes comportamentos copye deep copyoperações dizem respeito apenas a objetos compostos (ou seja: objetos que contêm outros objetos, como listas).

Aqui estão as diferenças ilustradas neste exemplo de código simples:

Primeiro

vamos verificar como copy(raso) se comporta, criando uma lista original e uma cópia desta lista:

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

Agora, vamos executar alguns printtestes e ver como a lista original se compara à sua lista de cópias:

original_list e copy_list têm endereços diferentes

print(hex(id(original_list)), hex(id(copy_list))) # 0x1fb3030 0x1fb3328

elementos da lista original e lista de cópias têm os mesmos endereços

print(hex(id(original_list[1])), hex(id(copy_list[1]))) # 0x537ed440 0x537ed440

sub_elements de original_list e copy_list têm os mesmos endereços

print(hex(id(original_list[5])), hex(id(copy_list[5]))) # 0x1faef08 0x1faef08

modificar elementos da lista original NÃO modifica os elementos da lista cópia

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

modificar elementos copy_list NÃO modifica elementos 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]

modificar sub_elements da lista original modificar automaticamente sub_elementos da cópia

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]

modificar sub_elementos copy_list modificar automaticamente 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]

Segundo

vamos verificar como deepcopyse comporta, fazendo o mesmo que fizemos com copy(criando uma lista original e uma cópia desta lista):

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

Agora, vamos executar alguns printtestes e ver como a lista original se compara à sua lista de cópias:

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

original_list e copy_list têm endereços diferentes

print(hex(id(original_list)), hex(id(copy_list))) # 0x1fb3030 0x1fb3328

elementos da lista original e lista de cópias têm os mesmos endereços

print(hex(id(original_list[1])), hex(id(copy_list[1]))) # 0x537ed440 0x537ed440

sub_elements de original_list e copy_list têm endereços diferentes

print(hex(id(original_list[5])), hex(id(copy_list[5]))) # 0x24eef08 0x24f3300

modificar elementos da lista original NÃO modifica os elementos da lista cópia

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

modificar elementos copy_list NÃO modifica elementos 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]

modificar sub_elements da lista original NÃO modifica os sub_elementos da cópia

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]

modificar sub_elementos copy_list NÃO modifica 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]
Fouad Boukredine
fonte
0

Não tenho certeza se isso foi mencionado acima ou não, mas é muito importante entender que .copy () cria referência ao objeto original. Se você alterar o objeto copiado - você altera o objeto original. .deepcopy () cria um novo objeto e faz uma cópia real do objeto original para um novo. Alterar um novo objeto copiado em profundidade não afeta o objeto original.

E sim, .deepcopy () copia o objeto original recursivamente, enquanto .copy () cria um objeto de referência para dados de primeiro nível do objeto original.

Portanto, a diferença de cópia / referência entre .copy () e .deepcopy () é significativa.

remort
fonte
0

A cópia profunda está relacionada a estruturas aninhadas. Se você tiver uma lista de listas, copie em profundidade as listas aninhadas também, portanto, é uma cópia recursiva. Com apenas copiar, você tem uma nova lista externa, mas listas internas são referências. A atribuição não copia. Para Ex

import copy
spam = [[0, 1, 2, 3], 4, 5]
cheese = copy.copy(spam)
cheese.append(3)
cheese[0].append(3)
print(spam)
print(cheese)

Resultado

[[0, 1, 2, 3, 3], 4, 5] [[0, 1, 2, 3, 3], 4, 5, 3] Copie o método copiar o conteúdo da lista externa para uma nova lista, mas a lista interna é ainda é o mesmo para as duas listas. Se você fizer alterações na lista interna de qualquer lista, isso afetará as duas.

Mas se você usar a cópia Profunda, ela também criará uma nova instância para a lista interna.

import copy
spam = [[0, 1, 2, 3], 4, 5]
cheese = copy.deepcopy(spam)
cheese.append(3)
cheese[0].append(3)
print(spam)
print(cheese)

Resultado

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

Shubham Agarwal
fonte
-1
>>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.
sudhir tataraju
fonte
anão é uma cópia em profundidade de lst!
Georgy