2013-03-14 4 views
7

Der Operator is wird für die Identitätsprüfung verwendet.Verwendet der `is` -Operator eine __magic__-Methode in Python?

Ich frage mich, ob der is Operator und id() Funktionsaufruf jede __magic__ Methode, die Art und Weise ==__eq__ nennt.

hatte ich etwas Spaß __hash__ Check-out:

class Foo(object): 
    def __hash__(self): 
     return random.randint(0, 2 ** 32) 

a = Foo() 
b = {} 
for i in range(5000): 
    b[a] = i 

Denken Sie über dict b und dem Wert von b[a]

ist jeder nachfolgende Nachschlag von d[a] entweder ein KeyError oder eine zufällige ganze Zahl.

Aber als docs on the special methods Zustand

[die Standardimplementierung von] x. __hash__() gibt ID (x) zurück.

So gibt ist Beziehung zwischen den beiden, aber nur umgekehrt.

Ich habe viele questions auf is und id hier zu sehen, und die answers haben viele confused Köpfe geholfen, aber ich konnte keine Antwort auf diese finden.

+0

Ihr Beispiel ist eigentlich ziemlich amüsant. Favourited für das :) – nneonneo

+0

Diese Definition der Standard-'Hash' ist nicht richtig. In CPython ist 'PyBaseObject_Type.tp_hash'' lang _Py_HashPointer (void * p) {long x; size_t y = (Größe_t) p; y = (y >> 4) | (y << (8 * SIZEOF_VOID_P - 4)); x = (lang) y; if (x == -1) x = -2; return x;} 'Dies rotiert die Adresse um 4 Bits, um Hash-Kollisionen zu reduzieren, da die unteren 2-4 Bits der Adresse wahrscheinlich 0 sind. – eryksun

Antwort

14

Nein, is ist ein gerader Zeiger Vergleich und id gibt nur die Adresse des zu einem long Gussobjekt.

Von ceval.c:

case PyCmp_IS: 
    res = (v == w); 
    break; 
case PyCmp_IS_NOT: 
    res = (v != w); 
    break; 

v und w hier sind einfach PyObject *.

Von bltinmodule.c:

static PyObject * 
builtin_id(PyObject *self, PyObject *v) 
{ 
    return PyLong_FromVoidPtr(v); 
} 

PyDoc_STRVAR(id_doc, 
"id(object) -> integer\n\ 
\n\ 
Return the identity of an object. This is guaranteed to be unique among\n\ 
simultaneously existing objects. (Hint: it's the object's memory address.)"); 
+2

+1 für das Graben in die Quelle (für die ich zu faul war;)) –

+2

Eine Codezeile ist tausend Bilder wert. –

+0

Diese Antwort ist spezifisch für CPython; In anderen Implementierungen (mindestens Jython und PyPy) ist "is" kein Zeigervergleich, und "id" gibt die Adresse nicht zurück. – abarnert

9

Die kurze Antwort lautet: Nein, tun sie nicht. Da die docs zu sagen, die Sie verlinken auf:

Die Betreiber is und is not Test für Objektidentität: x is y ist wahr, wenn und nur wenn x und y das gleiche Objekt sind.

Als "dasselbe Objekt" darf man nicht überschreiben. Wenn Ihr Objekt nicht das gleiche Objekt wie das andere ist, kann es nicht vorgeben, es zu sein.


Also ... Warum? Was wäre der Schaden, den Sie haben, um is und/oder id außer Kraft zu setzen? Offensichtlich wäre es fast immer eine Dummheit, aber Python lässt eine Menge dummer Dinge tun, wenn man es hart genug versucht.

Die Design-FAQ und ähnliche Dokumente sagen nicht. Aber ich vermute, dass es in erster Linie darauf zurückzuführen ist, dass es Python und einige der tieferen Standard-Bibliotheksmodule leichter aus dem Interpreter heraus überprüft werden kann, um zu überprüfen, ob zwei Namen sich tatsächlich auf dasselbe Objekt beziehen oder ob sie ausgedruckt werden Die id, um sicherzustellen, dass ein Name im Laufe der Zeit nicht geändert hat, usw. Stellen Sie sich das Debuggen weakref oder sogar pickle, ohne dass.


Also, was genau bedeutet "dasselbe Objekt"? Nun, das liegt an dem Dolmetscher. Offensichtlich muss es unmöglich sein, zwei Instanzen desselben Objekts auf der Sprachebene und wahrscheinlich auch auf der Interpreterebene zu unterscheiden (insbesondere da es eine wohldefinierte API zum Einstecken in die meisten Interpreterimplementierungen gibt).

Alle großen Implementierungen handhaben dies, indem sie sich auf den Begriff der Identität auf der unteren Ebene verschieben. CPython vergleicht die Werte der PyObject* Zeiger, Jython identitäts vergleicht die Referenzen Java, tut PyPy eine is auf den Object Objekte ...

Es lohnt sich auf PyPy source suchen, die die "x is y iff x und y erfordert sind das gleiche Objekt "In beiden Richtungen wahr zu sein. Der Ausdruck auf oberster Ebene x is y ist wahr, wenn die Objekte wx und wy in dem entsprechenden Objektraum sind, wy.is_(wx) ist wahr, und is_ ist als implementiert. Also, x is y auf Ebene N iff y is x auf Ebene N-1.


Beachten Sie, dass dies bedeutet, dass Sie ziemlich leicht PyPy einen Dialekt von Python zu bauen verwenden könnten, wo iskann außer Kraft gesetzt wird, nur durch is_ zu einem dunder Verfahren __is__ auf dem höheren Niveau anzubringen. Aber es gibt einen einfacheren Weg, um die gleiche Sache zu tun:

def is_(x, y): 
    if hasattr(x, '__is__'): 
     return x.__is__(y) 
    elif hasattr(y, '__is__'): 
     return y.__is__(x) 
    else: 
     return x is y 

Jetzt mit is_(x, y) statt x is y spielen, und sehen Sie, wenn Sie keinen Spaß Probleme finden können, bevor die harte Arbeit der Modifizierung der Dolmetscher zu tun (auch wenn es isn‘ t so schwer, in diesem Fall).


Also, was macht is haben mit id zu tun? Konnte is oben auf id -eeg implementiert werden, x is y prüft gerade id(x) == id(y)? Nun, id:

Geben Sie die "Identität" eines Objekts zurück. Dies ist eine ganze Zahl, die garantiert für dieses Objekt während seiner Lebensdauer eindeutig und konstant ist. Zwei Objekte mit nicht überlappenden Lebensdauern können den gleichen Wert haben id(). So

, die id ein Objekt ist einzigartig und konstant während seiner Lebenszeit, und x is y ist wahr genau dann, wenn sie das gleiche Objekt sind, daher x is y ist wahr genau dann, wenn id(x) == id(y), nicht wahr?

Nun, id kann zu was auch immer Sie wollen Rebound sein, und das ist nicht erlaubt, is zu beeinflussen.Wenn Sie die Definition sehr sorgfältig erstellt haben (bedenken Sie, dass, wenn Sie den builtins Verweis auf id verwerfen, welche Implementierung auch immer vorhanden war, ist es nicht einmal mehr garantiert, oder es funktioniert, wenn es existiert ...), könnten Sie könnte Definieren Sie is über die Standardimplementierung von id.

Aber es wäre eine seltsame Sache zu tun. In CPython, wobei id(x) nur "die Adresse des Objekts im Speicher zurückgibt", was dasselbe ist wie der Wert des Zeigers auf das Objekt im Speicher. Aber das ist nur ein Artefakt von CPython; Es gibt nichts, das sagt, dass andere Implementierungen den zugrunde liegenden Wert zurückgeben müssen, der für Identitätsvergleich als eine ganze Zahl verwandt wird. In der Tat ist es nicht klar, wie Sie das in einer Implementierung in einer Sprache ohne Zeiger (die in Ganzzahlen umgewandelt werden kann) geschrieben haben. In PyPy kann der Wert id eines Objekts sogar ein Wert sein, der beim ersten Zugriff berechnet und in einem Verzeichnis im Objektraum gespeichert wird, das vom Objekt selbst eingegeben wird.


Was __hash__, sind Verlesen Sie einen wichtigen Teil der Dokumentation.

[...] x.__hash__() gibt id(x) zurück.

Der Teil, den Sie ellipsized macht deutlich, dass dies für Instanzen von benutzerdefinierten Klassen nur wahr ist (die __hash__ nicht neu definieren). Dies trifft beispielsweise nicht auf tuple zu. Kurz gesagt, Identität hat nichts mit Hashing zu tun, außer dass für einige Objekte die Identität einen passenden Hash-Wert ergibt.

+2

"Wenn Ihr Objekt nicht das gleiche Objekt ist wie das andere, kann es nicht so aussehen." +1 – mgilson

Verwandte Themen