83 votes

Comment créer une liste de taille fixe en python ?

En C++, je peux créer un tableau comme...

int* a = new int[10];

En python, je sais juste que je peux déclarer une liste, puis ajouter quelques éléments, ou comme

l = [1,2,3,4]
l = range(10)

Puis-je initialiser une liste par une taille donnée, comme en c++, et ne pas faire d'affectation ?

112voto

ninjagecko Points 25709

(tl;dr : La réponse exacte à votre question est numpy.empty o numpy.empty_like mais il est probable que vous ne vous en souciez pas et que vous pouvez vous en tirer avec l'utilisation de myList = [None]*10000 .)

Des méthodes simples

Vous pouvez initialiser votre liste avec le même élément. C'est à vous de décider si, d'un point de vue sémantique, il est judicieux d'utiliser une valeur non numérique (qui provoquera une erreur plus tard si vous l'utilisez, ce qui est une bonne chose) ou quelque chose comme 0 (inhabituel ? peut-être utile si vous écrivez une matrice peu dense ou si la valeur "par défaut" devrait être 0 et que vous ne vous souciez pas des bogues) :

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

(Ici _ n'est qu'un nom de variable, vous auriez pu utiliser i .)

Vous pouvez également procéder comme suit :

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

Il n'est probablement pas nécessaire de l'optimiser. Vous pouvez également ajouter des éléments au tableau chaque fois que vous en avez besoin :

>>> x = []
>>> for i in range(10):
>>>    x.append(i)

Comparaison des performances des méthodes simples

Quelle est la meilleure solution ?

>>> def initAndWrite_test():
...  x = [None]*10000
...  for i in range(10000):
...   x[i] = i
... 
>>> def initAndWrite2_test():
...  x = [None for _ in range(10000)]
...  for i in range(10000):
...   x[i] = i
... 
>>> def appendWrite_test():
...  x = []
...  for i in range(10000):
...   x.append(i)

Résultats en python2.7 :

>>> import timeit
>>> for f in [initAndWrite_test, initAndWrite2_test, appendWrite_test]:
...  print('{} takes {} usec/loop'.format(f.__name__, timeit.timeit(f, number=1000)*1000))
... 
initAndWrite_test takes 714.596033096 usec/loop
initAndWrite2_test takes 981.526136398 usec/loop
appendWrite_test takes 908.597946167 usec/loop

Résultats en python 3.2 :

initAndWrite_test takes 641.3581371307373 usec/loop
initAndWrite2_test takes 1033.6499214172363 usec/loop
appendWrite_test takes 895.9040641784668 usec/loop

Comme nous pouvons le voir, il est probablement préférable d'utiliser l'idiome [None]*10000 en python2 et python3. Cependant, si l'on fait quelque chose de plus compliqué que l'assignation (comme quelque chose de compliqué pour générer ou traiter chaque élément de la liste), alors l'overhead devient une fraction insignifiante du coût. En d'autres termes, il est prématuré de s'inquiéter d'une telle optimisation si vous faites quelque chose de raisonnable avec les éléments de votre liste.


Mémoire non initialisée

Toutes ces méthodes sont cependant inefficaces parce qu'elles passent par la mémoire, en écrivant quelque chose au cours du processus. En C, c'est différent : un tableau non initialisé est rempli avec de la mémoire poubelle aléatoire (note de bas de page : qui a été réallouée par le système, et qui peut être un risque de sécurité lorsque vous allouez ou ne verrouillez pas et/ou ne supprimez pas la mémoire lorsque vous fermez le programme). Il s'agit d'un choix de conception, destiné à accélérer les choses : les concepteurs du langage C pensaient qu'il valait mieux ne pas initialiser automatiquement la mémoire, et c'était le bon choix.

Il ne s'agit pas d'une accélération asymptotique (parce qu'il s'agit de O(N) ), mais par exemple, vous n'auriez pas besoin d'initialiser tout votre bloc de mémoire avant de l'écraser avec des éléments qui vous intéressent vraiment. Si c'était possible, cela équivaudrait à quelque chose comme (pseudo-code) x = list(size=10000) .

Si vous voulez quelque chose de similaire en python, vous pouvez utiliser la fonction numpy progiciel de manipulation de matrices numériques/réseaux à neuf dimensions. En particulier, numpy.empty o numpy.empty_like

Telle est la véritable réponse à votre question.

15voto

jadkik94 Points 6274

Vous pouvez utiliser ceci : [None] * 10 . Mais il ne s'agit pas d'une "taille fixe" : vous pouvez toujours ajouter, supprimer ... C'est ainsi que les listes sont faites.

Vous pourriez en faire un tuple ( tuple([None] * 10) ) pour fixer sa largeur, mais là encore, vous ne pourrez pas la modifier (pas dans tous les cas, seulement si les éléments stockés sont mutables).

Une autre option, plus proche de votre besoin, n'est pas une liste, mais un collections.deque avec une longueur maximale. C'est la taille maximale, mais elle pourrait être plus petite.

import collections
max_4_items = collections.deque([None] * 4, maxlen=4)

Mais il suffit d'utiliser une liste et de s'habituer à la manière "pythonique" de faire les choses.

8voto

Rolf of Saxony Points 1695

Il s'agit plus d'un avertissement que d'une réponse.
Ayant vu dans les autres réponses my_list = [None] * 10 Je me suis laissé tenter et j'ai créé un tableau comme celui-ci speakers = [['','']] * 10 et a fini par le regretter immensément, car les résultats de la list ne s'est pas comportée comme je le pensais.
J'ai eu recours à :

speakers = []
for i in range(10):
    speakers.append(['',''])

En tant que [['','']] * 10 semble créer une list où les éléments suivants sont une copie du premier élément.
par exemple :

>>> n=[['','']]*10
>>> n
[['', ''], ['', ''], ['', ''], ['', ''], ['', ''], ['', ''], ['', ''], ['', ''], ['', ''], ['', '']]
>>> n[0][0] = "abc"
>>> n
[['abc', ''], ['abc', ''], ['abc', ''], ['abc', ''], ['abc', ''], ['abc', ''], ['abc', ''], ['abc', ''], ['abc', ''], ['abc', '']]
>>> n[0][1] = "True"
>>> n
[['abc', 'True'], ['abc', 'True'], ['abc', 'True'], ['abc', 'True'], ['abc', 'True'], ['abc', 'True'], ['abc', 'True'], ['abc', 'True'], ['abc', 'True'], ['abc', 'True']]

Considérant qu'avec le .append option :

>>> n=[]
>>> for i in range(10):
...  n.append(['',''])
... 
>>> n
[['', ''], ['', ''], ['', ''], ['', ''], ['', ''], ['', ''], ['', ''], ['', ''], ['', ''], ['', '']]
>>> n[0][0] = "abc"
>>> n
[['abc', ''], ['', ''], ['', ''], ['', ''], ['', ''], ['', ''], ['', ''], ['', ''], ['', ''], ['', '']]
>>> n[0][1] = "True"
>>> n
[['abc', 'True'], ['', ''], ['', ''], ['', ''], ['', ''], ['', ''], ['', ''], ['', ''], ['', ''], ['', '']]

Je suis sûr que la réponse acceptée de ninjagecko tente de mentionner ce point, malheureusement j'étais trop épais pour comprendre.
En conclusion, prenez soin de vous !

7voto

Vlad Bezden Points 5024

Vous pouvez le faire en utilisant réseau Le module array fait partie de la bibliothèque standard de Python :

from array import array
from itertools import repeat

a = array("i", repeat(0, 10))
# or
a = array("i", [0]*10)

répéter répète 10 fois la valeur 0. Elle est plus efficace en termes de mémoire que [0]*10, puisqu'elle n'alloue pas de mémoire, mais répète le même nombre x fois.

4voto

BluePeppers Points 1573

Ce n'est pas vraiment la manière python d'initialiser des listes de cette manière. Quoi qu'il en soit, vous pouvez initialiser une liste comme ceci :

>>> l = [None] * 4
>>> l
[None, None, None, None]

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X