Was sind „is' und „id' in Python?

巴扎黑
Freigeben: 2017-04-30 16:28:49
Original
1989 Leute haben es durchsucht

(ob1 ist ob2) ist äquivalent zu (id(ob1) == id(ob2))

Erstens kann die ID-Funktion die Speicheradresse des Objekts abrufen. Wenn die Speicheradressen der beiden Objekte gleich sind, müssen die beiden Objekte ein Objekt sein. ist äquivalent zu ist. Python-Quellcode als Beweis.

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;
Nach dem Login kopieren

​Aber sehen Sie bitte im folgenden Code, wie diese Situation auftritt?

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
Nach dem Login kopieren

Zwei Objekte werden anhand von „is“ als „falsch“ beurteilt, sind jedoch „wahr“, wenn sie anhand von „id“ beurteilt werden. Dies steht im Widerspruch zu den uns bekannten Fakten. Wie lässt sich dieses Phänomen erklären? Die beste Lösung für diese Situation besteht darin, das Modul dis aufzurufen, um zu sehen, was die beiden Vergleichsanweisungen bewirken.

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)
Nach dem Login kopieren

Die tatsächliche Situation ist, dass bei der Ausführung des .-Operators tatsächlich ein Proxy-Objekt generiert wird. Wenn foo.bar gleich Foo.bar ist, werden zwei Objekte nacheinander generiert und auf dem Stapel verglichen. Da die Adressen unterschiedlich sind, muss dies der Fall sein. Aber es ist anders, wenn id(foo.bar) == id(Foo.bar) generiert wird und dann die Adresse von foo.bar berechnet wird Objekt, das auf foo.bar zeigt, daher wird das foo.bar-Objekt freigegeben. Generieren Sie dann das Foo.bar-Objekt. Da foo.bar und Foo.bar dieselbe Speichergröße belegen, wird die Speicheradresse der ursprünglichen foo.bar wiederverwendet, also id(foo.bar) == id(Foo. bar ) ist wahr.

Der folgende Inhalt wird von Leo Jay per E-Mail bereitgestellt. Er erklärt ihn klarer.

Die Idee, id(Ausdruck a) == id(Ausdruck b) zu verwenden, um zu bestimmen, ob die Ergebnisse zweier Ausdrücke dasselbe Objekt sind, ist problematisch.

Diese Form von foo.bar wird als Attributreferenz [1] bezeichnet und ist eine Art Ausdruck. foo ist ein Instanzobjekt und bar ist eine Methode. Zu diesem Zeitpunkt wird das vom Ausdruck foo.bar zurückgegebene Ergebnis als Methodenobjekt [2] bezeichnet. Laut Dokumentation:

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.
Nach dem Login kopieren

foo.bar selbst ist kein einfacher Name, sondern das Berechnungsergebnis eines Ausdrucks, der ein Methodenobjekt ist. In einem Ausdruck wie id(foo.bar) ist das Methodenobjekt nur eine temporäre Zwischenvariable Variablen als IDs verwenden.

Ein offensichtlicheres Beispiel ist

print id(foo.bar) == id(foo.__init__)
Nach dem Login kopieren

Das Ausgabeergebnis ist ebenfalls True

​Schauen Sie sich die Dokumentation von id[3] an:

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.
Nach dem Login kopieren

Nur wenn Sie garantieren können, dass das Objekt nicht zerstört wird, können Sie id zum Vergleichen zweier Objekte verwenden. Wenn Sie also unbedingt vergleichen möchten, müssen Sie so schreiben:

fb = foo.bar 
Fb = Foo.bar 
print id(fb) == id(Fb)
Nach dem Login kopieren

Das heißt, Sie können das richtige Ergebnis erhalten, indem Sie die Ergebnisse der beiden Ausdrücke an die Namen binden und dann vergleichen, ob es sich um dasselbe Objekt handelt.

Das Gleiche gilt für den is-Ausdruck [4]. Das korrekte Ergebnis, das Sie jetzt erhalten, ist ausschließlich auf die aktuellen Implementierungsdetails von CPython zurückzuführen. Die aktuelle Implementierung besteht darin, die Objekte auf der linken und rechten Seite zu berechnen und dann zu vergleichen, ob die Adressen der beiden Objekte gleich sind. Wenn es sich eines Tages ändert, berechnen Sie zuerst die linke Seite, speichern Sie die Adresse, geben Sie die linke Seite frei, berechnen Sie dann die rechte Seite und vergleichen Sie erneut. Das Ergebnis Ihrer Berechnung ist möglicherweise falsch. Dieses Problem wird auch in der offiziellen Dokumentation erwähnt [5]. Ich denke, die richtige Methode ist wie bei id. Berechnen Sie zuerst sowohl die linke als auch die rechte Seite und binden Sie sie explizit an ihren jeweiligen Namen, und verwenden Sie sie dann zur Beurteilung.

[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

Das obige ist der detaillierte Inhalt vonWas sind „is' und „id' in Python?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Verwandte Etiketten:
Quelle:php.cn
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage