Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

210
Views
¿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 answers
Answer question

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 Report

0

Como se señaló en esta pregunta , la comprensión de lista 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(i)

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 Report

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 Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!