HOWTO · Python

Cómo copiar un diccionario en Python

Aprende cuándo la asignación crea un alias de un diccionario, cuándo basta una copia superficial y cuándo necesitas una copia profunda para independizar los valores anidados.

En esta página

Para crear un diccionario externo nuevo, usa dict(source) o source.copy(). Ambas opciones crean copias superficiales: los valores anidados siguen compartidos. Usa copy.deepcopy(source) cuando también necesites que los valores mutables anidados sean independientes. La asignación con = no crea una copia. Para ampliar la información, consulta el tutorial de diccionarios de Python y la documentación del módulo copy de Python.

Asignar un diccionario crea un alias

La asignación vincula otro nombre al mismo objeto diccionario. Cualquier cambio en el diccionario realizado mediante uno de los nombres también se ve a través del otro. Volver a asignar un nombre es distinto: hace que ese nombre apunte a otro objeto, sin cambiar el objeto original ni el otro nombre.

En este ejemplo completo, se modifica el diccionario compartido mediante meal y, después, se asigna a meal un diccionario nuevo:

food = {"Fruit": "Orange", "Vegetable": "Lettuce"}
meal = food
meal["Fruit"] = "Banana"
print(food)
print(meal)
meal = {"Fruit": "Apple"}
print(food)
print(meal)
{'Fruit': 'Banana', 'Vegetable': 'Lettuce'}
{'Fruit': 'Banana', 'Vegetable': 'Lettuce'}
{'Fruit': 'Banana', 'Vegetable': 'Lettuce'}
{'Fruit': 'Apple'}

Los dos primeros valores impresos coinciden porque, en ese momento, ambos nombres hacen referencia al mismo objeto. Después de la asignación a meal, solo ese nombre apunta al diccionario recién creado; food sigue haciendo referencia al original. Esta distinción explica por qué un cambio en un valor realizado mediante un nombre también se ve mediante el otro, mientras que reasignar una variable no reemplaza el objeto al que hace referencia la otra.

Variables de Python que hacen referencia al mismo diccionario

Crear una copia superficial de un diccionario

El constructor integrado dict() y el método copy() de un diccionario crean cada uno un diccionario externo nuevo. Actualizar o eliminar una entrada de nivel superior en esa copia no modifica el original. Sin embargo, ambos diccionarios siguen haciendo referencia a las mismas listas, diccionarios u otros valores mutables anidados, así que los cambios en esos valores pueden verse a través de ambos nombres.

Aquí, by_constructor y by_method tienen cada uno su propio diccionario externo. La lista anidada se comparte, mientras que asignar un valor nuevo a la clave name solo afecta a la copia elegida:

source = {"name": "Sherlock", "numbers": [1, 2, 3]}
by_constructor = dict(source)
by_method = source.copy()
by_constructor["name"] = "Holmes"
by_constructor["numbers"][1] = 4
print(source)
print(by_constructor)
print(by_method)
{'name': 'Sherlock', 'numbers': [1, 4, 3]}
{'name': 'Holmes', 'numbers': [1, 4, 3]}
{'name': 'Sherlock', 'numbers': [1, 4, 3]}

Elige cualquiera de estas formas de copia superficial cuando necesites que el diccionario externo sea independiente y te parezca bien compartir los valores anidados. Una copia superficial no copia de forma recursiva los objetos anidados. Por ejemplo, asignar un valor distinto a by_constructor["name"] deja sin cambios el valor de name en el diccionario de origen, porque esa clave pertenece a cada diccionario externo por separado. En cambio, cambiar un elemento de numbers se refleja en los tres diccionarios impresos porque la lista es compartida. Lo mismo ocurre si un valor es otro diccionario: la copia de nivel superior conserva una referencia a ese diccionario interno. Si solo necesitas aislar un valor anidado, puedes copiarlo por separado; usa una copia profunda si necesitas que toda la estructura anidada sea independiente.

Copia superficial de Python que muestra un diccionario externo nuevo

Copiar profundamente un diccionario anidado

Cuando también necesites copias independientes de los valores mutables anidados, usa copy.deepcopy(). Esta función copia recursivamente los objetos contenidos, por lo que el ejemplo siguiente puede cambiar un elemento de una lista y un valor de un diccionario interno sin modificar el original. Es útil para los datos anidados que planeas editar por separado; no hace falta si quieres compartir los valores anidados.

import copy

source = {
    "numbers": [1, 2, 3],
    "address": {"city": "Miami"},
}
independent = copy.deepcopy(source)
independent["numbers"][1] = 4
independent["address"]["city"] = "Lexington"
print(source)
print(independent)
{'numbers': [1, 2, 3], 'address': {'city': 'Miami'}}
{'numbers': [1, 4, 3], 'address': {'city': 'Lexington'}}

Una copia profunda resulta útil cuando quieres que los cambios posteriores no se propaguen entre la estructura de origen y una copia de trabajo, por ejemplo, al preparar una versión de una configuración anidada para modificarla por separado. También copia los contenedores anidados, no solo el diccionario externo; por eso la lista y el diccionario address interno permanecen sin cambios en el ejemplo. En estructuras grandes, una copia profunda puede requerir más tiempo y memoria que una superficial, así que elígela según necesites o no objetos anidados independientes. Los objetos de Python pueden personalizar su comportamiento de copia, y algunos recursos no se pueden duplicar de forma significativa; si trabajas con ellos, consulta la documentación del módulo copy.

La elección práctica depende de qué objetos quieras compartir: la asignación comparte el diccionario entero, una copia superficial separa solo el diccionario externo y una copia profunda separa también los objetos anidados. La documentación del módulo copy explica cómo se comportan las copias superficiales y profundas con objetos compuestos y con objetos que personalizan el comportamiento de copia.