Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

174
Visualizações
¿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 Respostas
Responde à pergunta

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 Relatório

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 Relatório

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 Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda