Quelqu'un peut-il expliquer ce qui suit?
Pourquoi l'identifiant est-il le même, mais les listes sont différentes?
>>> [] is []
False
>>> id([]) == id([])
True
Y a-t-il une différence dans la création d'une liste?
>>> id(list()) == id(list())
False
>>> id([]) == id([])
True
Pourquoi cela arrive-t-il? Je reçois deux listes différentes. Pourquoi pas seulement un ou trois ou plus?
>>> [].__repr__
<method-wrapper '__repr__' of list object at 0x7fd2be868128>
>>> [].__repr__
<method-wrapper '__repr__' of list object at 0x7fd2be868170>
>>> [].__repr__
<method-wrapper '__repr__' of list object at 0x7fd2be868128>
>>> [].__repr__
<method-wrapper '__repr__' of list object at 0x7fd2be868170>
Vous avez mal utilisé id()
. id([])
prend l'identifiant mémoire d'un objet qui est jeté immédiatement. Après tout, rien n'y fait référence une fois que id()
en a fini. Ainsi, la prochaine fois que vous utiliserez id([])
Python voit une opportunité de réutiliser la mémoire et voilà, ces adresses sont en effet les mêmes.
Cependant, il s'agit d'un détail d'implémentation, sur lequel vous ne pouvez pas compter, et il ne sera pas toujours en mesure de réutiliser l'adresse mémoire.
Notez que les valeurs de id()
sont uniquement uniques pour la durée de vie de l'objet, voir documentation :
Il s'agit d'un entier qui est garanti unique et constant pour cet objet pendant sa durée de vie. Deux objets dont la durée de vie ne se chevauche pas peuvent avoir la même valeur
id()
.
(Souligné par moi).
Cette id(list())
ne peut pas réutiliser l'emplacement mémoire est probablement due aux mutations de tas supplémentaires provoquées en poussant le cadre actuel sur la pile pour appeler une fonction, puis en la réécrivant lorsque la fonction list()
retour d'appel.
[]
Et list()
produisent un nouvel objet de liste vide; mais vous devez d'abord créer des références à ces listes distinctes (ici a
et b
):
>>> a, b = [], []
>>> a is b
False
>>> id(a) == id(b)
False
>>> a, b = list(), list()
>>> a is b
False
>>> id(a) == id(b)
False
La même chose se produit lorsque vous avez utilisé [].__repr__
. L'interpréteur interactif Python a un nom global spécial, _
, Que vous pouvez utiliser pour référencer le dernier résultat produit:
>>> [].__repr__
<method-wrapper '__repr__' of list object at 0x10e011608>
>>> _
<method-wrapper '__repr__' of list object at 0x10e011608>
Cela crée une référence supplémentaire, donc la méthode __repr__
Et, par extension, la liste vide que vous avez créée pour elle, sont toujours considérées comme actives. L'emplacement mémoire n'est pas libéré et n'est pas disponible pour la prochaine liste que vous créez.
Mais en exécutant à nouveau [].__repr__
, Python lie désormais _
À ce nouvel objet de méthode. Du coup, la méthode __repr__
Précédente n'est plus référencée par rien et peut être libéré, tout comme l'objet liste.
La troisième fois que vous exécutez [].__repr__
, Le premier emplacement de mémoire est à nouveau disponible pour réutilisation, donc Python fait exactement cela:
>>> [].__repr__ # create a new method
<method-wrapper '__repr__' of list object at 0x10e00cb08>
>>> _ # now _ points to the new method
<method-wrapper '__repr__' of list object at 0x10e00cb08>
>>> [].__repr__ # so the old address can be reused
<method-wrapper '__repr__' of list object at 0x10e011608>
Vous ne créez jamais plus de deux listes; le précédent (toujours référencé par _
) et l'actuel. Si vous souhaitez voir plus d'emplacements de mémoire, utilisez des variables pour ajouter une autre référence.