2013-04-12 14 views
10

Miałem błąd, w którym polegałem na metodach równych sobie nawzajem podczas używania is. Okazuje się, że tak nie jest:Dlaczego metody nie mają równości odniesienia?

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

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

Dlaczego tak się dzieje? To działa dla zwykłych funkcji: obiekty

>>> def func(): 
    pass 

>>> func is func 
True 
+3

Działa w języku Python 3 btw. – poke

Odpowiedz

19

metodą są tworzone każdym razem, gdy je dostępu. Funkcje działają jak descriptors, wracając obiekt metody, gdy ich metoda .__get__ nazywa się:

>>> 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>> 

Zastosowanie == testowania równości zamiast.

Dwie metody są równe, jeśli ich atrybuty są identyczne: .im_self i .im_func. Jeśli chcesz przetestować, że metody reprezentują ten sam bazowy funkcja przetestować swoje im_func atrybuty:

>>> 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

Jeśli użyję '==', otrzymam zachowanie tożsamości, którego szukałem? – Claudiu

+0

Myślę, że metoda równości sprawdza tożsamość dla '.im_self', a nie dla równości. [sprawdź to] (http://pastebin.com/mSbDWUna) – Claudiu

+0

@Claudiu: tak, przepraszam, testuje, czy 'im_self' jest identyczny. –

1

Martijn ma rację, że nowe metody są obiekty generowane przez .__get__ więc ich wskaźniki adresowych nie utożsamiają ze związkiem is oszacowanie. Zauważ, że używanie == będzie oceniać zgodnie z zamierzeniami w Pythonie 2.7.

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 

jednak zauważyć, że użyte metody z przykładu nie są równe tym z grupy odniesienia, ponieważ odniesienia siebie prowadzone wraz ze sposobem z przykładu.

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

W Pythonie 3.3 operatora is metod częściej zachowuje się tak samo jak == więc uzyskać oczekiwane zachowanie, a nie w tym przykładzie. Wynika to z zaniku zarówno __cmp__, jak i czystszej reprezentacji obiektu metody w Pythonie 3; Metody mają teraz __eq__, a referencje nie są obiektami wbudowanymi, więc zachowanie jest zgodne z oczekiwaniami bez oczekiwań Pythona 2.

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

Twoja analiza jest wyłączona. Zmiany zaobserwowane w Pythonie 3 nie są powiązane z 'is'; wynikają one ze zniknięcia niezwiązanych obiektów metod w Pythonie 3. "Test.meth" jest teraz tylko zdefiniowanym obiektem funkcji raw, zamiast niezwiązanego obiektu metody utworzonego w locie. – user2357112

+0

Ahh tak, dodałem kilka wyjaśnień, aby uwzględnić problem związany z niezwiązanym obiektem. – Pyrce

Powiązane problemy