Heim > Artikel > Backend-Entwicklung > Was sind „is“ und „id“ in Python?
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;
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
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)
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.
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__)
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.
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)
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!