Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

161
Vistas
¿Por qué dos listas idénticas tienen una huella de memoria diferente?

Creé dos listas l1 y l2 , pero cada una con un método de creación diferente:

 import sys l1 = [None] * 10 l2 = [None for _ in range(10)] print('Size of l1 =', sys.getsizeof(l1)) print('Size of l2 =', sys.getsizeof(l2))

Pero la salida me sorprendió:

 Size of l1 = 144 Size of l2 = 192

La lista creada con una lista por comprensión tiene un tamaño mayor en la memoria, pero las dos listas son idénticas en Python por lo demás.

¿Porqué es eso? ¿Es esto algo interno de CPython o alguna otra explicación?

over 4 years ago · Santiago Trujillo
3 Respuestas
Responde la pregunta

0

Cuando escribe [None] * 10 , Python sabe que necesitará una lista de exactamente 10 objetos, por lo que asigna exactamente eso.

Cuando usa una lista de comprensión, Python no sabe cuánto necesitará. Por lo tanto, la lista crece gradualmente a medida que se agregan elementos. Para cada reasignación, asigna más espacio del que se necesita inmediatamente, de modo que no tiene que reasignar para cada elemento. Es probable que la lista resultante sea un poco más grande de lo necesario.

Puede ver este comportamiento al comparar listas creadas con tamaños similares:

 >>> sys.getsizeof([None]*15) 184 >>> sys.getsizeof([None]*16) 192 >>> sys.getsizeof([None for _ in range(15)]) 192 >>> sys.getsizeof([None for _ in range(16)]) 192 >>> sys.getsizeof([None for _ in range(17)]) 264

Puede ver que el primer método asigna solo lo que se necesita, mientras que el segundo crece periódicamente. En este ejemplo, asigna suficiente para 16 elementos y tuvo que reasignar al llegar al 17.

over 4 years ago · Santiago Trujillo Denunciar

0

Como se señaló en esta pregunta , la comprensión de listas usa list.append bajo el capó, por lo que llamará al método de cambio de tamaño de lista, que sobreasigna.

Para demostrarte esto a ti mismo, puedes usar el dis :

 >>> code = compile('[x for x in iterable]', '', 'eval') >>> import dis >>> dis.dis(code) 1 0 LOAD_CONST 0 (<code object <listcomp> at 0x10560b810, file "", line 1>) 2 LOAD_CONST 1 ('<listcomp>') 4 MAKE_FUNCTION 0 6 LOAD_NAME 0 (iterable) 8 GET_ITER 10 CALL_FUNCTION 1 12 RETURN_VALUE Disassembly of <code object <listcomp> at 0x10560b810, file "", line 1>: 1 0 BUILD_LIST 0 2 LOAD_FAST 0 (.0) >> 4 FOR_ITER 8 (to 14) 6 STORE_FAST 1 (x) 8 LOAD_FAST 1 (x) 10 LIST_APPEND 2 12 JUMP_ABSOLUTE 4 >> 14 RETURN_VALUE >>>

Observe el código de operación LIST_APPEND en el desensamblado del objeto de código <listcomp> . De los documentos :

LIST_APPEND(yo)

Lista de llamadas.append list.append(TOS[-i], TOS) . Se utiliza para implementar listas de comprensión.

Ahora, para la operación de repetición de lista, tenemos una pista sobre lo que está pasando si consideramos:

 >>> import sys >>> sys.getsizeof([]) 64 >>> 8*10 80 >>> 64 + 80 144 >>> sys.getsizeof([None]*10) 144

Por lo tanto, parece ser capaz de asignar exactamente el tamaño. Mirando el código fuente , vemos que esto es exactamente lo que sucede:

 static PyObject * list_repeat(PyListObject *a, Py_ssize_t n) { Py_ssize_t i, j; Py_ssize_t size; PyListObject *np; PyObject **p, **items; PyObject *elem; if (n < 0) n = 0; if (n > 0 && Py_SIZE(a) > PY_SSIZE_T_MAX / n) return PyErr_NoMemory(); size = Py_SIZE(a) * n; if (size == 0) return PyList_New(0); np = (PyListObject *) PyList_New(size);

Es decir, aquí: size = Py_SIZE(a) * n; . El resto de las funciones simplemente llena la matriz.

over 4 years ago · Santiago Trujillo Denunciar

0

Ninguno es un bloque de memoria, pero no es un tamaño preespecificado. Además de eso, hay un espacio adicional en una matriz entre los elementos de la matriz. Puedes verlo tú mismo ejecutando:

 for ele in l2: print(sys.getsizeof(ele)) >>>>16 16 16 16 16 16 16 16 16 16

Lo cual no totaliza el tamaño de l2, sino que es menor.

 print(sys.getsizeof([None])) 72

Y esto es mucho mayor que una décima parte del tamaño de l1 .

Sus números deberían variar según los detalles de su sistema operativo y los detalles del uso actual de la memoria en su sistema operativo. El tamaño de [Ninguno] nunca puede ser mayor que la memoria adyacente disponible donde la variable está configurada para almacenarse, y es posible que la variable deba moverse si luego se asigna dinámicamente para que sea más grande.

over 4 years ago · Santiago Trujillo Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda