Comment créer une liste avec une taille spécifique en Python

  1. Préallocation de l’espace de stockage pour les listes
  2. Préallocation de la mémoire pour d’autres structures de données séquentielles

La pré-allocation de mémoire pour des listes ou des tableaux est un schéma typique chez les programmeurs quand ils connaissent le nombre d’éléments à l’avance.

Contrairement à C++ et Java, en Python, vous devez initialiser tout votre stockage pré-alloué avec quelques valeurs. Habituellement, les développeurs utilisent de fausses valeurs dans ce but, telles que None, False, 0.

Python offre plusieurs façons de créer une liste de taille fixe, chacune avec différentes caractéristiques de performance.

Pour comparer les performances des différentes approches, nous utiliserons le standard Python module timeit. Il fournit un moyen pratique de mesurer le temps d’exécution de petits morceaux de code Python.

Préallocation de l’espace de stockage pour les listes

La première et la plus rapide façon d’utiliser l’opérateur *, qui répète une liste a spécifié nombre de fois.

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

Un million d’itérations (valeur par défaut des itérations dans timeit) prennent environ 117 ms.

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

Une autre approche consiste à utiliser la fonction intégrée range avec une compréhension de liste.

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

C’est presque six fois plus lent et prend 612 ms par million d’itérations.

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

La troisième approche est d’utiliser une simple boucle for avec la fonction list.append().

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

L’utilisation de boucles est la méthode la plus lente et prend 842 ms pour compléter un million d’itérations.

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

Préallocation de la mémoire pour d’autres structures de données séquentielles

Puisque vous pré-allouez du stockage pour une structure de données séquentielle, il peut être très judicieux d’utiliser la structure de données intégrée array au lieu d’une liste.

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

Comme nous le voyons ci-dessous, cette approche est la deuxième plus rapide après [None] * 10.

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

Comparons les approches Python pures ci-dessus au paquet Python NumPy pour le calcul scientifique.

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

La méthode NumPy prend 589 ms par million d’itérations.

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

Cependant, la méthode NumPy sera beaucoup plus rapide pour des listes plus massives.

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

La conclusion est qu’il est préférable de s’en tenir à [None] * 10 pour les petites listes, mais de passer à la empty() de NumPy lorsqu’il s’agit de données séquentielles plus massives.

Article connexe - Python List

  • Comment trouver des doublons dans une liste en Python
  • Comment passer en boucle plusieurs listes en Python