ProgramaciónDesarrollador de Python

¿Cuáles son los principios de funcionamiento de los administradores de memoria en listas y tuplas de Python? ¿Cuál es la diferencia entre cambiar/agregar elementos en una lista y una tupla y cómo afecta esto al rendimiento?

Supere entrevistas con el asistente de IA Hintsage

Respuesta

En Python, las listas (list) son estructuras mutables, mientras que las tuplas (tuple) son inmutables.

  • list: Al agregar nuevos elementos (append, extend, insert), Python asigna bloques de memoria "con reserva" para minimizar la cantidad de asignaciones cuando el arreglo crece ("estrategia de sobre-asignación"). La eliminación de elementos (pop, remove) ocurre rápidamente, pero a veces puede causar la redistribución de memoria.
  • tuple: El tamaño de la tupla es constante; los elementos no pueden ser modificados o añadidos, lo que asegura una alta velocidad de las operaciones de lectura y un menor consumo de memoria en comparación con las listas al almacenar grandes cantidades de datos inmutables.

Ejemplo que ilustra el cambio en list y tuple:

lst = [1, 2, 3] lst.append(4) # OK lst[1] = 20 # OK tup = (1, 2, 3) tup[1] = 20 # TypeError

Rendimiento:

  • Las listas son ideales para colecciones que cambian con frecuencia.
  • Las tuplas son un poco más rápidas, utilizan la memoria de manera más eficiente (debido a su tamaño constante y principios de hash), y son adecuadas para claves de diccionarios, valores de retorno de funciones (datos inmutables).

Pregunta trampa

Pregunta: ¿Por qué las operaciones de agregar elementos a una lista suelen ser rápidas (O(1)), si desde el punto de vista de un arreglo deberían llevar a la redistribución de memoria?

Respuesta:

Python implementa arreglos dinámicos "con reserva de memoria" de inmediato para varios elementos. Por lo tanto, append generalmente toma O(1), y la redistribución de memoria ocurre solo cuando el bloque reservado se agota realmente.

Ejemplo:

import sys lst = [] for i in range(10): lst.append(i) print(len(lst), sys.getsizeof(lst)) # El tamaño de la memoria no crece de forma estrictamente lineal

Historia

Ejemplo 1

En un proyecto, se usaron list para las claves de un diccionario. El desarrollador no sabía que las listas no se pueden hashear (mutabilidad), lo que provocó el error "TypeError: unhashable type: 'list'".


Ejemplo 2

El desarrollador a menudo creaba listas largas concatenándolas a través de +. Esto resultaba en copias adicionales del arreglo y altos costos de memoria y tiempo. Era más eficiente usar append en un ciclo o generadores.


Ejemplo 3

En el sistema de registro, se eligieron tuplas para almacenar marcas de tiempo, pensando que por ser inmutables sería más rápido. Pero de vez en cuando surgía la necesidad de modificarlas, lo que requería crear nuevas tuplas constantemente (copy-on-write) y llevaba a una disminución del rendimiento en comparación con el uso de listas.