Cópia Superficial e Cópia Profunda no Python

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.

  1. 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
  1. 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]
  1. 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]
  1. 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
  1. 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.

Tags: Python copy module shallow copy deep copy mutability

Publicado em 6-28 18:40