En Python, il existe deux types similaires - liste (liste) et tuple (tuple). La différence la plus célèbre entre les deux est que les tuples sont immuables.
Vous ne pouvez pas modifier les objets dans le tuple:
>>> a = (1,2,3) >>> a[0] = 10 Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: 'tuple' object does not support item assignment
Mais vous pouvez modifier des objets mutables à l'intérieur d'un tuple:
>>> b = (1,[1,2,3],3) >>> b[1] [1, 2, 3] >>> b[1].append(4) >>> b (1, [1, 2, 3, 4], 3)
Dans CPython (l'interpréteur standard), la liste et le tuple sont implémentés comme une feuille de pointeurs (liens) vers des objets Python, c'est-à-dire physiquement, ils ne stockent pas d'objets côte à côte. Lorsque vous supprimez un objet de la liste, la référence à cet objet est supprimée. Si quelqu'un d'autre fait référence à l'objet, il continuera à être en mémoire.
Tuples
Malgré le fait que les tuples sont beaucoup moins courants dans le code et moins populaires, il s'agit d'un type très fondamental que Python utilise constamment à des fins internes.
Vous ne le remarquerez peut-être pas, mais vous utilisez des tuples lorsque:
- travailler avec des arguments ou des paramètres (ils sont stockés sous forme de tuples)
- retourner deux ou plusieurs variables d'une fonction
- itérer les clés de valeur dans un dictionnaire
- utiliser la mise en forme des chaînes
En règle générale, le script le plus simple utilise des milliers de tuples:
>>> import gc >>> def type_stats(type_obj): ... count = 0 ... for obj in gc.get_objects(): ... if type(obj) == type_obj: ... count += 1 ... return count ... >>> type_stats(tuple) 3136 >>> type_stats(list) 659 >>> import pandas >>> type_stats(tuple) 6953 >>> type_stats(list) 2455
Listes vides vs tuples vides
Un tuple vide fonctionne comme un singleton, c'est-à-dire il n'y a toujours qu'un seul tuple vide dans la mémoire d'un script Python en cours d'exécution. Tous les tuples vides se réfèrent simplement au même objet, cela est possible car les tuples sont immuables. Cette approche économise beaucoup de mémoire et accélère le processus de travail avec des tuples vides.
>>> a = () >>> b = () >>> a is b True >>> id(a) 4409020488 >>> id(b) 4409020488 >>>
Mais cela ne fonctionne pas avec les listes, car elles peuvent être modifiées:
>>> a = [] >>> b = [] >>> a is b False >>> id(a) 4465566920 >>> id(b) 4465370632
Optimisation de l'allocation de mémoire pour les tuples
Afin de réduire la fragmentation de la mémoire et d'accélérer la création de tuples, Python réutilise les anciens tuples qui ont été supprimés. Si un tuple se compose de moins de 20 éléments et n'est plus utilisé, alors au lieu de le supprimer, Python le place dans une liste spéciale qui stocke des tuples libres de réutilisation.
Cette liste est divisée en 20 groupes, où chaque groupe est une liste de tuples de taille n, où n est compris entre 0 et 20. Chaque groupe peut stocker jusqu'à 2 000 tuples gratuits. Le premier groupe stocke un seul élément et est une liste d'un tuple vide.
>>> a = (1,2,3) >>> id(a) 4427578104 >>> del a >>> b = (1,2,4) >>> id(b) 4427578104
Dans l'exemple ci-dessus, nous pouvons voir que a et b ont la même adresse en mémoire. Cela est dû au fait que nous avons instantanément pris un tuple gratuit de la même taille.
Optimisation de l'allocation de mémoire pour les listes
Les listes étant susceptibles de changer, la même optimisation que dans le cas des tuples ne peut plus être augmentée. Malgré cela, les listes utilisent des optimisations similaires visant des listes vides. Si la liste vide est supprimée, elle peut également être réutilisée à l'avenir.
>>> a = [] >>> id(a) 4465566792 >>> del a >>> b = [] >>> id(b) 4465566792
Redimensionner la liste
Pour éviter les frais généraux liés au redimensionnement constant des listes, Python ne le redimensionne pas chaque fois qu'il est requis. Au lieu de cela, chaque liste possède un ensemble de cellules supplémentaires qui sont masquées pour l'utilisateur, mais peuvent ensuite être utilisées pour de nouveaux éléments. Dès la fin des cellules cachées, Python ajoute de l'espace supplémentaire pour de nouveaux éléments. Et il le fait avec une bonne marge, le nombre de cellules cachées est sélectionné en fonction de la taille actuelle de la liste - plus elle est grande, plus il y a d'emplacements cachés supplémentaires pour les nouveaux éléments.
Cette optimisation est particulièrement utile lorsque vous essayez d'ajouter de nombreux éléments dans une boucle.
Le modèle de croissance de la taille de la liste ressemble à ceci: 0, 4, 8, 16, 25, 35, 46, 58, 72, 88, ...
Par exemple, si vous souhaitez ajouter un nouvel élément à une liste de 8 éléments, il n'y aura pas de cellules libres et Python étendra immédiatement sa taille à 16 cellules, dont 9 d'entre elles seront occupées et visibles par l'utilisateur.
Formule de dimensionnement Python:
>>> def get_new_size(n_items): ... new_size = n_items + (n_items // 2 ** 3) ... if n_items < 9: ... new_size += 3 ... else: ... new_size += 6 ... ... return new_size ... >>> get_new_size(9) 16
La vitesse
Si nous comparons ces deux types de vitesse, puis en moyenne dans un hôpital, les tuples sont légèrement plus rapides que les listes. Raymond Hettinger a une excellente explication de la différence de vitesse sur
stackoverflow .
PS: je suis l'auteur de cet article, vous pouvez poser toutes vos questions.