¿Por qué los métodos no tienen igualdad de referencia?

Tuve un error en el que confiaba en que los métodos son iguales entre sí cuando se usa. Resulta que ese no es el caso:

 >>> class What(object): def meth(self): pass >>> What.meth is What.meth False >>> inst = What() >>> inst.meth is inst.meth False 

¿Por qué es ese el caso? Funciona para funciones regulares:

 >>> def func(): pass >>> func is func True 

Los objetos de método se crean cada vez que se accede a ellos . Las funciones actúan como descriptores y devuelven un objeto de método cuando se llama a su método .__get__ :

 >>> What.__dict__['meth']  >>> What.__dict__['meth'].__get__(None, What)  >>> What.__dict__['meth'].__get__(What(), What) > 

Use == pruebas de igualdad en su lugar.

Dos métodos son iguales si sus .im_self y .im_func son idénticos. Si necesita probar que los métodos representan la misma función subyacente, pruebe sus atributos im_func :

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

Martijn tiene razón al decir que los nuevos Métodos son objetos generados por .__get__ por lo que los punteros de sus direcciones no coinciden con una evaluación. Tenga en cuenta que el uso de == se evaluará según lo previsto en Python 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 

Sin embargo, tenga en cuenta que los métodos a los que se hace referencia desde una instancia no son equivalentes a los que se mencionan en la clase debido a la propia referencia que se lleva junto con el método de una instancia.

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

En Python 3.3, el operador para métodos se comporta con mayor frecuencia como == por lo que en este ejemplo se obtiene el comportamiento esperado. Esto resulta de la desaparición de __cmp__ y de una representación del objeto del método más limpio en Python 3; los métodos ahora tienen __eq__ y las referencias no son objetos construidos sobre la marcha, por lo que el comportamiento sigue como podría esperarse sin las expectativas de Python 2.

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