Copiar um Dicionário em Python

  1. Copiar um Dicionário em Python: Passagem por referência
  2. Copiar um Dicionário em Python: Passar por Valor
  3. Cópia rasa do Python Dictionary

Este tutorial discute como se pode copiar um dicionário em Python.

Vamos demonstrar como copiar um dicionário de duas maneiras: passando por valor e passando por referência.

Copiar um Dicionário em Python: Passagem por referência

Em Python, os objectos não são implicitamente copiados. Se tentarmos copiar food para uma nova variável meal, os valores de food serão copiados para meal, mas também o será a referência de food.

meal = food

A equiparação directa de um objecto a outro fará com que o novo objecto aponte para o anterior; isto significa que as duas variáveis farão referência ao mesmo objecto único.

Se actualizarmos o valor Fruit em meal para Banana, o valor de Fruit em food será também substituído.

meal['Fruit'] = 'Banana'
print(food)
print(meal)

Resultado:

{'Fruit': 'Banana', 'Vegetable': 'Lettuce', 'Poultry': 'Chicken', 'Fish': 'Cod'}
{'Fruit': 'Banana', 'Vegetable': 'Lettuce', 'Poultry': 'Chicken', 'Fish': 'Cod'}

O mesmo acontece se tentarmos actualizar uma chave no bloco meal. Substituiremos a chave Fruit por Circle Fruit e copiaremos o seu valor antes de o retirarmos do dicionário.

meal['Circle Fruit'] = meal.pop('Fruit')
print(food)
print(meal)

Resultado:

{'Vegetable': 'Lettuce', 'Poultry': 'Chicken', 'Fish': 'Cod', 'Circle Fruit': 'Orange'}
{'Vegetable': 'Lettuce', 'Poultry': 'Chicken', 'Fish': 'Cod', 'Circle Fruit': 'Orange'}

O valor de food ainda será substituído mesmo que não o tenhamos modificado directamente; isto porque o método que utilizámos para copiar food para meal passa por referência.

Copiar dicionário Python - Passar por referência

Copiar um Dicionário em Python: Passar por Valor

Passar por valor significa que uma cópia real do objecto será criada na memória, em vez de apontar a cópia para o objecto original ao copiar um objecto.

Se quisermos copiar um dicionário e evitar a referência aos valores originais, então devemos encontrar uma forma de instanciar um novo objecto na memória. Em Python, existem algumas funções que apoiam esta abordagem: dict(), copy(), e deepcopy().

A função dict() instantia um novo objecto de dicionário. Se envolver um dicionário existente em torno desta função, será criada uma nova instância do objecto.

Para este método, vamos utilizar o mesmo exemplo do dicionário food.

meal = dict(food)

Outra forma de passar por valor é utilizando o comando copy(), que faz a mesma coisa que dict() faz: instanciar um novo objecto na memória. A diferença é que copy() é uma função integrada de objectos de colecção, incluindo dicionários.

meal = food.copy()

Para ambos os cenários, vamos modificar o valor Fruit e substituir a chave Vegetable:

meal['Fruit'] = 'Apple'
meal['Greens'] = meal.pop('Vegetable')
print(food)
print(meal)

Resultado:

{'Fruit': 'Orange', 'Vegetable': 'Lettuce', 'Poultry': 'Chicken', 'Fish': 'Cod'} # food (original)
{'Fruit': 'Apple', 'Poultry': 'Chicken', 'Fish': 'Cod', 'Greens': 'Lettuce'} # meal (copy)

Ao instanciar um novo objecto meal utilizando dict() ou copy(), evitamos a referência ao objecto original e a actualização dos seus valores se a meal for actualizada.

Cópia rasa do Python Dictionary

O problema com dict() e copy() é que eles só aplicam uma cópia superficial ao objecto a ser utilizado; isto será um problema se o seu dicionário tiver uma estrutura aninhada complexa.

A cópia rasa apenas copiará a primeira camada na memória que vê porque os objectos aninhados ocupam novos espaços.

Dicionário de cópia Python - Cópia Rápida

Vamos mudar o objecto original para um dicionário aninhado.

info = { "Numbers": [1, 2, 3],
         "Resident Name": "Sherlock",
         "Address": {"Street": "Baker",
                    "Number": "221B",
                    "City": "Miami"
                    }
       }

Vamos declarar um novo objecto info2 utilizando copy() e dict() para copiar de info e alterar alguns valores no dicionário aninhado.

info2 = info.copy() # or dict(info)
info2['Numbers'][1] = 4
info2["Resident Name"] = "Holmes"
info2["Address"]["City"] = "Lexington"
print(info)
print(info2)

Resultado:

{'Numbers': [1, 4, 3], 'Resident Name': 'Sherlock', 'Address': {'Street': 'Baker', 'Number': '221B', 'City': 'Lexington'}}
{'Numbers': [1, 4, 3], 'Resident Name': 'Holmes', 'Address': {'Street': 'Baker', 'Number': '221B', 'City': 'Lexington'}}

Os novos valores de Numbers e Address.City são actualizados tanto na versão original como na versão de cópia. O valor Resident Name apenas actualizou o bloco info2 porque só executámos uma cópia rasa no objecto.

Cópia profunda com o módulo copy em Python

A cópia profunda resolve essencialmente o problema da cópia superficial. Ao copiar um objecto, verifica a existência de objectos aninhados e cria recursivamente novos objectos na memória.

Em Python, podemos conseguir uma cópia profunda com o módulo copy, que contém operações e utilidades de cópia rasa e profunda.

import copy

Utilizaremos a função deepcopy() do módulo para copiar em profundidade os objectos aninhados dentro do nosso dicionário. Utilizaremos o mesmo exemplo do bloco info acima.

info2 = copy.deepcopy(info)
info2['Numbers'][1] = 4
info2["Resident Name"] = "Holmes"
info2["Address"]["City"] = "Lexington"
print(info)
print(info2)

Resultado:

{'Numbers': [1, 2, 3], 'Resident Name': 'Sherlock', 'Address': {'Street': 'Baker', 'Number': '221B', 'City': 'Miami'}}
{'Numbers': [1, 4, 3], 'Resident Name': 'Holmes', 'Address': {'Street': 'Baker', 'Number': '221B', 'City': 'Lexington'}}

Agora, o dicionário original info permanece inalterado, mesmo com as múltiplas alterações no info2, incluindo os objectos aninhados.

Em resumo, há muitas maneiras de copiar um dicionário em Python, mas a saída não será a mesma para todos. A atribuição directa de um dicionário com = passa-o por referência, apontando para o objecto original.

Funções de cópia rasa como dict() e copy() resolverão esse problema apenas para dicionários não aninhados. A melhor maneira de copiar um dicionário, considerando dicionários aninhados, é utilizar a função deepcopy() fornecida pelo módulo copy.

Artigo relacionado - Python Dictionary

  • Como ordenar o dicionário por chave em Python
  • Encontrar chave por valor no Python Dicionário