Em Python, atribuir um objeto a outra variável apenas cria uma nova referência para o mesmo valor em memória. Para obter estruturas independentes, é preciso entender a diferença entre cópia superficial e cópia profunda.
- Atribuição
A atribuição não duplica o objeto; ela aponta para o endereço já existente.
origem = {"servidor": "web01", "limites": [80, 90]}
referencia = origem
print(referencia is origem) # True
- Cópia superficial
Cria um novo contêiner na camada externa, mas mantém as mesmas referências para os objetos internos. Listas, dicionários e conjuntos aninhados continuam compartilhados.
Formas comuns de cópia superficial:
- Fatia:
lista[:] - Método:
dict.copy() - Construtor:
list(lista) - Módulo
copy:copy.copy(obj)
import copy
origem = {
"host": "db01",
"limiares": [70, 85]
}
superficial = copy.copy(origem)
# O contêiner externo é diferente...
print(id(origem) == id(superficial)) # False
# ...mas a lista interna é a mesma.
print(id(origem["limiares"]) == id(superficial["limiares"])) # True
superficial["limiares"][0] = 99
print(origem["limiares"]) # [99, 85]
- Cópia profunda
Recursivamente recria todos os objetos aninhados, produzindo uma estrutura totalmente independente.
import copy
origem = {
"host": "db01",
"limiares": [70, 85]
}
profunda = copy.deepcopy(origem)
print(id(origem) == id(profunda)) # False
print(id(origem["limiares"]) == id(profunda["limiares"])) # False
profunda["limiares"][0] = 99
print(origem["limiares"]) # [70, 85]
print(profunda["limiares"]) # [99, 85]
- Tipos imutáveis e internamento
Para números e strings, Python pode reutilizar o mesmo objeto em memória devido à otimização de imutáveis. Por isso, atribuição, cópia superficial e cópia profunda podem apresantar o mesmo id.
import copy
a = 123
b = copy.copy(a)
c = copy.deepcopy(a)
print(id(a), id(b), id(c)) # ids idênticos
s = "exemplo"
print(id(s) == id(copy.deepcopy(s))) # True
- Aplicação prática: modelo de alertas
Imagine um modelo de alertas que precisa ser customizado sem alterar o padrão original. Usar cópia profunda garente que a alteração do limite de CPU na nova instância não afete o modelo base.
import copy
modelo_padrao = {
"cpu": [80],
"memoria": [80],
"disco": [80]
}
modelo_custom = copy.deepcopy(modelo_padrao)
modelo_custom["cpu"][0] = 75
print(modelo_custom) # {'cpu': [75], 'memoria': [80], 'disco': [80]}
print(modelo_padrao) # {'cpu': [80], 'memoria': [80], 'disco': [80]}
Com uma cópia superficial, a lista interna seria compartilhada e a mudança se propagaria para o modelo padrão.
modelo_custom2 = copy.copy(modelo_padrao)
modelo_custom2["cpu"][0] = 75
print(modelo_padrao) # {'cpu': [75], ...}
Fatias de sequências e o método dict.copy() também são cópias superficiais. Portanto, ao trabalhar com estruturas aninhadas, prefira copy.deepcopy quando a independência total for neecessária.