En bref:
Python crée en interne un C
liste de tuple objets dont le premier élément contient le tuple vide. Chaque fois tuple()
ou ()
est utilisé, Python sera de retour l'objet existant contenues dans ladite C
liste et de ne pas en créer un nouveau.
Un tel mécanisme n'existe pas pour l' dict
ou list
objets qui sont, au contraire, recréé à partir de zéro à chaque fois.
Ceci est probablement lié au fait que les objets immuables (comme les n-uplets) ne peut pas être modifié et, comme tels, sont garantis de ne pas changer au cours de l'exécution. C'est encore renforcée si l'on considère que frozenset() is frozenset()
retours True
; comme ()
vide frozenset
est considéré comme un singleton dans la mise en œuvre de l' CPython
. Avec mutable objets, ces garanties ne sont pas en place et, en tant que tel, il n'y a pas d'incitation à cache leur zéro de l'élément de cas (j'.e leur contenu pourrait changer avec l'identité en restant le même).
Prenez note: Ce n'est pas quelque chose que l'on devrait dépendre de l', j'.e que l'on ne devrait pas envisager de vide tuples sont des singletons. Pas de telles garanties sont explicitement dans la documentation il faut donc supposer qu'il est dépendant de l'implémentation.
Comment c'est fait:
Dans le cas le plus fréquent, la mise en œuvre de l' CPython
est compilé avec les deux macros PyTuple_MAXFREELIST
et PyTuple_MAXSAVESIZE
ensemble de nombres entiers positifs. La valeur positive pour ces macros résultats dans la création d'un tableau de tuple
objets avec la taille de l' PyTuple_MAXSAVESIZE
.
Lors de l' PyTuple_New
est appelée avec le paramètre size == 0
il fait en sorte d' ajouter un nouveau tuple vide à la liste si elle n'existe pas déjà:
if (size == 0) {
free_list[0] = op;
++numfree[0];
Py_INCREF(op); /* extra INCREF so that this is never freed */
}
Ensuite, si un nouveau tuple est demandé, celui qui se trouve dans la première position de cette liste va se retourné au lieu d'une nouvelle instance:
if (size == 0 && free_list[0]) {
op = free_list[0];
Py_INCREF(op);
/* rest snipped for brevity.. */
Une raison supplémentaire provoquant une incitation à faire c'est le fait que les appels de fonction construire un n-uplet de tenir la position des arguments qui vont être utilisés. Ceci peut être vu dans l' load_args
fonction ceval.c
:
static PyObject *
load_args(PyObject ***pp_stack, int na)
{
PyObject *args = PyTuple_New(na);
/* rest snipped for brevity.. */
qui est appelé via do_call
dans le même fichier. Si le nombre d'arguments, na
est égal à zéro, un tuple vide va être retournés.
En substance, cela pourrait être une opération qui est réalisée le plus souvent il est donc logique de ne pas reconstruire un tuple vide à chaque fois.
Pour en savoir plus:
Un couple plus de réponses éclairer CPython
's la mise en cache de comportement avec immutables:
- Pour les entiers, une autre réponse que de fouilles dans la source peut être trouvé ici.
- Pour les chaînes, une poignée de réponses peuvent être trouvées ici, ici et ici.