Maison  >  Article  >  développement back-end  >  Que sont l'is et l'identifiant apparaissant en Python ?

Que sont l'is et l'identifiant apparaissant en Python ?

巴扎黑
巴扎黑original
2017-04-30 16:28:491977parcourir

(ob1 est ob2) équivaut à (id(ob1) == id(ob2))

Premièrement, la fonction id peut obtenir l'adresse mémoire de l'objet. Si les adresses mémoire des deux objets sont les mêmes, alors les deux objets doivent être un seul objet. est équivalent à est. Code source Python comme preuve.

static PyObject *
 cmp_outcome(int op, register PyObject *v, register PyObject *w)
{
 int res = 0;
 switch (op) {
 case PyCmp_IS:
  res = (v == w);
 break;
 case PyCmp_IS_NOT:
res = (v != w);
 break;

Mais veuillez voir comment cette situation se produit dans le code ci-dessous ?

In [1]: def bar(self, x):
...:     return self.x + y
...: 

In [2]: class Foo(object):
...:     x = 9
...:     def __init__(self ,x):
...:         self.x = x
...:     bar = bar
...:     

In [3]: foo = Foo(5)

In [4]: foo.bar is Foo.bar
Out[4]: False

In [5]: id(foo.bar) == id(Foo.bar)
Out[5]: True

Deux objets sont jugés faux en utilisant is, mais sont vrais lorsqu'ils sont jugés en utilisant id. Ceci est incompatible avec les faits que nous connaissons. Comment expliquer ce phénomène ? La meilleure solution à cette situation est d'appeler le module dis pour voir ce que font les deux instructions de comparaison.

In [7]: dis.dis("id(foo.bar) == id(Foo.bar)")
          0 BUILD_MAP       10340
          3 BUILD_TUPLE     28527
          6 <46>           
          7 DELETE_GLOBAL   29281 (29281)
         10 STORE_SLICE+1  
         11 SLICE+2        
         12 DELETE_SUBSCR  
         13 DELETE_SUBSCR  
         14 SLICE+2        
         15 BUILD_MAP       10340
         18 PRINT_EXPR     
         19 JUMP_IF_FALSE_OR_POP 11887
         22 DELETE_GLOBAL   29281 (29281)
         25 STORE_SLICE+1  

In [8]: dis.dis("foo.bar is Foo.bar")
          0 BUILD_TUPLE     28527
          3 <46>           
          4 DELETE_GLOBAL   29281 (29281)
          7 SLICE+2        
          8 BUILD_MAP        8307
         11 PRINT_EXPR     
         12 JUMP_IF_FALSE_OR_POP 11887
         15 DELETE_GLOBAL   29281 (29281)

La situation réelle est que lorsque l'opérateur . est exécuté, un objet proxy est réellement généré. Lorsque foo.bar est Foo.bar, deux objets sont générés séquentiellement et comparés sur la pile. Parce que les adresses sont différentes, elles doivent être fausses. mais c'est différent quand id(foo.bar) == id(Foo.bar). Tout d'abord, foo.bar est généré, puis l'adresse de foo.bar est calculée. Après avoir calculé l'adresse de foo.bar, il n'y en a pas. objet pointant vers foo .bar, donc l'objet foo.bar sera libéré. Générez ensuite l'objet Foo.bar. Puisque foo.bar et Foo.bar occupent la même taille de mémoire, l'adresse mémoire du foo.bar d'origine est réutilisée, donc id(foo.bar) == id(Foo. bar. ) est vrai.

Le contenu suivant est fourni par Leo Jay par e-mail. Il l'explique plus clairement.

L'idée d'utiliser id(expression a) == id(expression b) pour déterminer si les résultats de deux expressions sont le même objet est problématique.

Cette forme de foo.bar est appelée référence d'attribut [1], qui est un type d'expression. foo est un objet instance et bar est une méthode. À ce stade, le résultat renvoyé par l'expression foo.bar est appelé objet méthode [2]. D'après la documentation :

When an instance attribute is referenced that isn’t a data attribute, 
its class is searched. If the name denotes a valid class attribute 
that is a function object, a method object is created by packing 
(pointers to) the instance object and the function object just found 
together in an abstract object: this is the method object.

foo.bar lui-même n'est pas un simple nom, mais le résultat du calcul d'une expression, qui est un objet méthode. Dans une expression telle que id(foo.bar), l'objet méthode n'est qu'une variable intermédiaire temporaire. pour utiliser des variables comme identifiants.

Un exemple plus évident est

print id(foo.bar) == id(foo.__init__)

Le résultat de sortie est également vrai

​Regardez la documentation de id[3] :

Return the “identity” of an object. This is an integer (or long 
integer) which is guaranteed to be unique and constant for this object 
during its lifetime. Two objects with non-overlapping lifetimes may 
have the same id() value. 
CPython implementation detail: This is the address of the object in memory.

Ce n'est que si vous pouvez garantir que l'objet ne sera pas détruit que vous pourrez utiliser id pour comparer deux objets. Alors, si vous insistez pour comparer, vous devez écrire ainsi :

fb = foo.bar 
Fb = Foo.bar 
print id(fb) == id(Fb)

Autrement dit, vous pouvez obtenir le résultat correct en liant les résultats des deux expressions aux noms, puis en comparant s'il s'agit du même objet.

La même chose est vraie pour l'expression is [4]. Le résultat correct que vous obtenez maintenant est entièrement dû aux détails d'implémentation actuels de CPython. L'implémentation actuelle consiste à calculer les objets sur les côtés gauche et droit, puis à comparer si les adresses des deux objets sont les mêmes. S'il est modifié un jour, calculez d'abord le côté gauche, enregistrez l'adresse, relâchez le côté gauche, puis calculez le côté droit et comparez à nouveau, le résultat de votre recherche peut être erroné. Ce problème est également mentionné dans la documentation officielle [5]. Je pense que la méthode correcte est comme l'identifiant, calculez d'abord les côtés gauche et droit, et liez-les explicitement à leurs noms respectifs, puis utilisez pour juger.

[1] http://docs.python.org/2/reference/expressions.html#attribute-references
[2] http://docs.python.org/2/tutorial/classes.html#method-objects
[3] http://docs.python.org/2/library/functions.html#id
[4] http://docs.python.org/2/reference/expressions.html#index-68
[5] http://docs.python.org/2/reference/expressions.html#id26

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn