47 votes

Pourquoi '() is ()' renvoie-t-il True lorsque '[] est []' et '{} est {}' renvoie False?

De ce que j'ai été conscient, à l'aide d' [], {} ou () pour instancier des objets retourne une nouvelle instance de list, dict ou tuple respectivement; une nouvelle instance de l'objet avec une nouvelle identité.

C'était assez clair pour moi jusqu'à ce que j'ai fait testé et j'ai remarqué qu' () is () renvoie en fait True à la place de l' False:

>>> () is (), [] is [], {} is {}
(True, False, False)

comme prévu, ce comportement est également manifesté lors de la création d'objets avec des list(), dict() et tuple() respectivement:

>>> tuple() is tuple(), list() is list(), dict() is dict()
(True, False, False)

La seule information que j'ai pu trouver dans les docs pour tuple() membres de:

[...] Par exemple, tuple('abc') retours ('a', 'b', 'c') et tuple([1, 2, 3]) retours (1, 2, 3). Si aucun argument n'est donné, le constructeur crée un nouveau tuple vide, ().

Il suffit de dire que ce n'est pas suffisant pour répondre à ma question.

Alors, pourquoi ne vide tuples ont la même identité, tandis que d'autres comme les listes ou les dictionnaires ne le font pas?

53voto

Jim Points 8793

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.

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