Cómo crear una lista con un tamaño específico en Python

  1. Preasignación de almacenamiento para listas
  2. Preasignación de almacenamiento para otras estructuras de datos secuenciales

La preasignación de almacenamiento para listas o arrays es un patrón típico entre los programadores cuando saben el número de elementos con antelación.

A diferencia de C++ y Java, en Python hay que inicializar todo el almacenamiento preasignado con algunos valores. Normalmente, los desarrolladores usan valores falsos para ese propósito, como None, False, y 0.

Python ofrece varias maneras de crear una lista de un tamaño fijo, cada una con diferentes características de rendimiento.

Para comparar el rendimiento de los diferentes enfoques, utilizaremos el estándar de Python módulo timeit. Proporciona una forma práctica de medir los tiempos de ejecución de pequeños trozos de código Python.

Preasignación de almacenamiento para listas

La primera y más rápida manera de usar el operador *, que repite una lista una vez especificada número de veces.

>>> [None] * 10
[None, None, None, None, None, None, None, None, None, None]

Un millón de iteraciones (valor por defecto de las iteraciones en timeit) toman aproximadamente 117 ms.

>>> timeit("[None] * 10")
0.11655918900214601

Otra aproximación es usar la función incorporada range con una comprensión de la lista.

>>> [None for _ in range(10)]
[None, None, None, None, None, None, None, None, None, None]

Es casi seis veces más lenta y tarda 612 ms segundo por millón de iteraciones.

>>> timeit("[None for _ in range(10)]")
0.6115895550028654

La tercera aproximación es usar un bucle simple for junto con el [list.append()]](https://docs.python.org/3/tutorial/datastructures.html).

>>> a = []
>>> for _ in range(10):
...   a.append(None)
...
>>> a
[None, None, None, None, None, None, None, None, None, None]

El uso de bucles es el método más lento y toma 842 ms para completar un millón de iteraciones.

>>> timeit("for _ in range(10): a.append(None)", setup="a=[]")
0.8420009529945673

Preasignación de almacenamiento para otras estructuras de datos secuenciales

Dado que está preasignando almacenamiento para una estructura de datos secuencial, puede tener mucho sentido utilizar la estructura de datos incorporada en array en lugar de una lista.

>>> from array import array
>>> array('i',(0,)*10)
array('i', [0, 0, 0, 0, 0, 0, 0, 0, 0, 0])

Como vemos a continuación, este enfoque es el segundo más rápido después de [None] * 10.

>>> timeit("array('i',(0,)*10)", setup="from array import array")
0.4557597979946877

Comparemos las aproximaciones a Python puro de arriba con el paquete Python NumPy para computación científica.

>>> from numpy import empty
>>> empty(10)
array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0.])

El camino de NumPy toma 589 ms por millón de iteraciones.

>>> timeit("empty(10)", setup="from numpy import empty")
0.5890094790011062

Sin embargo, el camino de NumPy será mucho más rápido para listas más masivas.

>>> timeit("[None]*10000")
16.059584009999526
>>> timeit("empty(10000)", setup="from numpy import empty")
1.1065983309963485

La conclusión es que es mejor atenerse a None * 10 para listas pequeñas, pero cambiar al empty() de NumPy cuando se trata de datos secuenciales más masivos.

Artículo relacionado - Python List

  • Convertir lista de cadenas a enteros en Python
  • Cómo obtener valores únicos de una lista en Python