Copiar listas
Aprende todas las formas de copiar una lista en Python: trampa de asignación, slicing, copy(), list() y deepcopy(), con ejemplos ejecutables y explicaciones claras.
Las listas de Python son mutables, lo que significa que asignar una lista a una nueva variable no crea una copia: ambos nombres apuntan al mismo objeto. Esta página explica todas las formas confiables de copiar una lista, la diferencia entre una copia superficial y una copia profunda, y cuándo cada enfoque es la opción correcta.
La trampa de la asignación
Un error común es usar el operador = esperando que produzca una copia independiente:
Por qué el operador = no copia una lista
Tanto original como alias apuntan exactamente al mismo objeto de lista en memoria. Cualquier cambio realizado a través de un nombre es inmediatamente visible a través del otro.
Para obtener una copia verdaderamente independiente, usa uno de los métodos que se muestran a continuación.
Métodos de copia superficial
Una copia superficial crea un nuevo objeto de lista, pero los elementos dentro de la nueva lista siguen siendo referencias a los mismos objetos que el original. Para una lista plana (una lista que contiene solo valores inmutables como números y cadenas), una copia superficial se comporta como una copia completamente independiente.
Usando el método copy()
El método copy() es el enfoque más explícito y legible:
Copiar una lista con el método copy()
original = ["apple", "banana", "cherry"]
copy_of = original.copy()
copy_of.append("date")
print(original) # Output: ['apple', 'banana', 'cherry']
print(copy_of) # Output: ['apple', 'banana', 'cherry', 'date']Las dos listas son ahora independientes: agregar elementos a copy_of no afecta a original.
Usando la notación de slice [:]
La notación de slice es un atajo Pythónico para copiar toda la lista:
Copiar una lista con notación de slice
original = [10, 20, 30, 40]
copy_of = original[:]
copy_of[0] = 99
print(original) # Output: [10, 20, 30, 40]
print(copy_of) # Output: [99, 20, 30, 40][:] se interpreta como "tomar cada elemento desde el inicio hasta el final", lo que produce una nueva lista con esos elementos.
Usando el constructor list()
Pasar una lista existente a list() también crea una copia superficial:
Copiar una lista con el constructor list()
original = [1, 2, 3]
copy_of = list(original)
copy_of.append(4)
print(original) # Output: [1, 2, 3]
print(copy_of) # Output: [1, 2, 3, 4]Esto es especialmente útil cuando se convierte otro iterable (como una tupla) en una lista al mismo tiempo.
Cuándo las copias superficiales no son suficientes
Una copia superficial solo copia la estructura de nivel superior. Si la lista contiene objetos mutables como otras listas o diccionarios, esos objetos anidados siguen siendo compartidos entre el original y la copia.
Copia superficial con una lista anidada
Ambas listas comparten los mismos objetos de lista internos [1, 2] y [3, 4]. Cambiar original[0][0] modifica esa lista interna compartida, por lo que el cambio también aparece en shallow.
Copia profunda
Una copia profunda copia recursivamente cada objeto dentro de la lista, produciendo una estructura completamente independiente del original. Usa copy.deepcopy() del módulo estándar copy:
Copia profunda de una lista anidada con copy.deepcopy()
import copy
original = [[1, 2], [3, 4]]
deep = copy.deepcopy(original)
original[0][0] = 99 # Mutate the nested list
print(original) # Output: [[99, 2], [3, 4]]
print(deep) # Output: [[1, 2], [3, 4]] <- unchangeddeep tiene sus propias copias de las listas internas, por lo que los cambios en original no le afectan en absoluto.
Copia superficial vs. copia profunda de un vistazo
| Método | ¿Crea una nueva lista? | ¿Copia objetos anidados? | Ideal para |
|---|---|---|---|
Asignación = | No | No | Solo alias |
copy() | Sí | No (superficial) | Listas planas |
Slicing [:] | Sí | No (superficial) | Listas planas |
list() | Sí | No (superficial) | Listas planas / iterables |
copy.deepcopy() | Sí | Sí | Estructuras anidadas |
Ejemplos prácticos
Combinando todos los métodos de copia superficial
original = [1, 2, 3]
a = original.copy() # method
b = original[:] # slice
c = list(original) # constructor
original.append(4)
print(a) # Output: [1, 2, 3]
print(b) # Output: [1, 2, 3]
print(c) # Output: [1, 2, 3]Los tres producen copias independientes: ninguna refleja el append(4) posterior.
Copiar una lista de diccionarios
Los diccionarios son objetos mutables. Una copia superficial de una lista de diccionarios comparte esos objetos dict:
import copy
records = [{"name": "Alice", "score": 90}, {"name": "Bob", "score": 85}]
shallow = records.copy()
deep = copy.deepcopy(records)
records[0]["score"] = 0
print(shallow[0]) # Output: {'name': 'Alice', 'score': 0} <- shared dict
print(deep[0]) # Output: {'name': 'Alice', 'score': 90} <- independent copyCuando los elementos son objetos mutables y necesitas independencia total, usa siempre deepcopy().
Conclusión
Las listas de Python son mutables, por lo que el operador = crea un alias, no una copia. Para listas planas, cualquiera de los métodos de copia superficial — copy(), [:] o list() — funciona igualmente bien. Cuando las listas contienen objetos mutables anidados, usa copy.deepcopy() para garantizar total independencia.
Para explorar operaciones relacionadas con listas, consulta Métodos de lista, Agregar elementos a una lista y Eliminar elementos de una lista. Para copiar diccionarios, aplica la misma distinción entre copia superficial y profunda — consulta Copiar diccionarios.