27 votes

Quelle est la différence entre "a est b" et "id(a) == id(b)" en Python?

La fonction intégrée id() donne...

un entier (ou un long entier) qui est garantit d'être unique et constant pour cet objet pendant sa durée de vie.

L'opérateur is, en revanche, renvoie...

l'identité de l'objet

Alors pourquoi est-il possible d'avoir deux objets qui ont le même id mais renvoient False à une vérification avec is? Voici un exemple:

>>> class Test():
...   def test():
...     pass
>>> a = Test()
>>> b = Test()
>>> id(a.test) == id(b.test)
True
>>> a.test is b.test
False

Un exemple plus préoccupant: (poursuivant l'exemple ci-dessus)

>>> b = a
>>> b is a
True
>>> b.test is a.test
False
>>> a.test is a.test
False

Cependant:

>>> nouvelle_methode_de_test_amelioree = lambda: None
>>> a.test = nouvelle_methode_de_test_amelioree
>>> a.test is a.test
True

46voto

Mike Graham Points 22480
>>> b.test is a.test
False
>>> a.test is a.test
False

Les méthodes sont créées à la volée chaque fois que vous les consultez. L'objet fonction (qui est toujours le même objet) implémente le protocole des descripteurs et son __get__ crée l'objet méthode liée. Normalement, aucun deux méthodes liées ne seraient le même objet.

>>> id(a.test) == id(b.test)
True
>>> a.test is b.test
False

Cet exemple est trompeur. Le résultat du premier est seulement True par coïncidence. a.test crée une méthode liée et elle est nettoyée par le ramasse-miettes après le calcul de id(a.test) car il n'y a pas de références à cette méthode. (Notez que vous avez cité la documentation disant qu'un id est "unique et constant pour cet objet pendant sa durée de vie" (soulignement ajouté).) b.test happen a le même id que la méthode liée que vous aviez avant et c'est autorisé car aucun autre objet n'a le même id maintenant.

Notez que vous devriez rarement utiliser is et encore moins utiliser id. id(foo) == id(bar) est toujours faux.


Concernant votre nouvel exemple, espérons que vous compreniez maintenant ce qu'il fait :

>>> new_improved_test_method = lambda: None
>>> a.test = new_improved_test_method
>>> a.test is a.test
True

Dans ce cas, nous ne créons pas des méthodes à la volée à partir de fonctions sur la classe en liant automatiquement self et renvoyant des objets méthode liée. Dans ce cas, vous stockez simplement une fonction en tant qu'attribut d'instance. Rien de spécial ne se produit lors de la recherche (les descripteurs ne sont appelés que lorsque vous recherchez un attribut de classe), donc à chaque fois que vous recherchez l'attribut, vous obtenez l'objet original que vous avez stocké.

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