2013-04-12 7 views
10

Ich hatte einen Fehler, bei dem ich mich auf Methoden verließ, die bei Verwendung von is gleich waren. Es stellt sich heraus, dass das nicht der Fall ist:Warum haben Methoden keine Referenzgleichheit?

>>> class What(object): 
    def meth(self): 
     pass 

>>> What.meth is What.meth 
False 
>>> inst = What() 
>>> inst.meth is inst.meth 
False 

Warum ist das der Fall? Es funktioniert für normale Funktionen:

>>> def func(): 
    pass 

>>> func is func 
True 
+3

Dies funktioniert in Python 3 btw. – poke

Antwort

19

Methode Objekte jedes Mal, wenn Sie auf sie zugreifen erstellt werden. Funktionen wirken als descriptors, ein Verfahren Objekt zurückkehren, wenn ihre .__get__ Methode aufgerufen wird:

>>> What.__dict__['meth'] 
<function meth at 0x10a6f9c80> 
>>> What.__dict__['meth'].__get__(None, What) 
<unbound method What.meth> 
>>> What.__dict__['meth'].__get__(What(), What) 
<bound method What.meth of <__main__.What object at 0x10a6f7b10>> 

Verwenden == Gleichheit Tests statt.

Zwei Methoden sind gleich, wenn ihre Attribute .im_self und .im_func identisch sind. Wenn Sie, dass die Methoden der gleichen zugrunde liegenden Funktion repräsentieren testen müssen, testen ihre im_func Attribute:

>>> What.meth == What.meth  # unbound methods (or functions in Python 3) 
True 
>>> What().meth == What.meth # unbound method and bound method 
False 
>>> What().meth == What().meth # bound methods with *different* instances 
False 
>>> What().meth.im_func == What().meth.im_func # functions 
True 
+0

Wenn ich '==' verwende, bekomme ich das Identitätsgleichheitsverhalten, nach dem ich gesucht habe? – Claudiu

+0

Ich denke, Methode Gleichheit überprüft die Identität für '.im_self', nicht die Gleichheit. [check it out] (http://pastebin.com/mSbDWUna) – Claudiu

+0

@Claudiu: Ja, tut mir leid, es testet, ob 'im_self' identisch ist. –

1

Martijn richtig ist, dass ein neuer Methoden Objekte von .__get__ erzeugten so ihre Adreßzeiger nicht gleichzusetzen mit einem is Bewertung. Beachten Sie, dass die Verwendung von == in Python 2.7 wie vorgesehen ausgewertet wird.

Python2.7 
class Test(object): 
    def tmethod(self): 
     pass 

>>> Test.meth is Test.meth 
False 
>>> Test.meth == Test.meth 
True 

>>> t = Test() 
>>> t.meth is t.meth 
False 
>>> t.meth == t.meth 
True 

beachte jedoch, dass von einer Instanz referenzierten Methoden nicht gleichzusetzen mit denen aus der Klasse referenziert, da die Referenz selbst zusammen mit dem Verfahren von einer Instanz ausgeführt.

>>> t = Test() 
>>> t.meth is Test.meth 
False 
>>> t.meth == Test.meth 
False 

In Python 3.3 die is Operator für Methoden verhält sich häufiger die gleiche wie die == so erhalten Sie das erwartete Verhalten, anstatt in diesem Beispiel. Dies ergibt sich sowohl aus __cmp__ verschwinden und eine sauberere Methode Objektdarstellung in Python 3; Methoden haben nun __eq__ und Verweise sind keine fliegenden Objekte, so dass das Verhalten folgt, wie man es erwarten könnte, ohne Python 2-Erwartungen.

Python3.3 
>>> Test.meth is Test.meth 
True 
>>> Test.meth == Test.meth 
True 
>>> Test.meth.__eq__(Test.meth) 
True 
+0

Ihre Analyse ist deaktiviert. Die Änderungen, die Sie in Python 3 beobachtet haben, beziehen sich nicht auf 'is'; Sie sind auf das Verschwinden von ungebundenen Methodenobjekten in Python 3 zurückzuführen. "Test.meth" ist jetzt nur das von Ihnen definierte unformatierte Funktionsobjekt anstelle eines ungebundenen Methodenobjekts, das im laufenden Betrieb erstellt wurde. – user2357112

+0

Ahh ja, ich habe einige klärende Details hinzugefügt, um das ungebundene Objektproblem einzubeziehen. – Pyrce