I am trying to port some python 2.7 classes I have into a C extension module -- well D actually, but that should not matter here.
One of my classes provides richcompare, for which two objects should compare equal if (appart from some C attributes) one of their types' methods is identical. For example, the desired behaviour would be (let mytype be the type that provides richcompare and 'method' the name of the instancemethod that needs comparison):
class X(mytype) :
def method(self) : pass
class Y(X) :
pass
class Z(X) :
def method(self) : pass
x=X(); y=Y(); z=Z()
x==y # True
x==z # False
I tried to implement this test in C by comparing the PyObject* pointers returned from
auto self_type = cast(PyObject*) py_self.ob_type;
auto other_type = cast(PyObject*) py_other.ob_type;
PyObject* self_method = PyObject_GetAttrString(self_type, "method");
PyObject* other_method = PyObject_GetAttrString(other_type, "method");
if (self_method != other_method) equal = false;
Py_XDECREF(self_method);
Py_XDECREF(other_method);
and was surprised that the two pointers are not equal, even when the TypeObjects are.
I then checked in plain python and indeed:
Python 2.7.12+ (default, Sep 17 2016, 12:08:02)
[GCC 6.2.0 20160914] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> class X(object) :
... def method(self) : pass
...
>>> x=X()
>>> type(x).method == X.method
True
>>> type(x).method is X.method
False
>>>
The returned methods are not identical. So, my two questions:
1) Why are the unbound methods X.method not identical?
2) How can I test their equality using the C API?
I worked it out now.
1) method lookup seems to create a new object that wraps the python function into a new object. This is why even
returns
False.2) PyMethod_Function(method) can be used to obtain the function (PyObject *) from the method object. This indeed implements the desired behaviour:
Robust code should check whether the respective attributes are indeed PyMethods before obtaining their functions.