如何比较 python/C 中的未绑定实例方法相等性

How to compare unbound instancemethod equality in python/C

我正在尝试移植一些 python 2.7 类 我有一个 C 扩展模块——实际上是 D,但这在这里无关紧要。

我的一个 类 提供了 richcompare,如果(从某些 C 属性来看)两个对象的其中一个类型的方法相同,则两个对象应该比较相等。例如,期望的行为是(让 mytype 成为提供 richcompare 的类型,'method' 需要比较的实例方法的名称):

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

我试图通过比较从

返回的 PyObject* 指针在 C 中实现这个测试
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);

令人惊讶的是两个指针不相等,即使 TypeObjects 相等。

然后我检查了普通 python 确实:

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

返回的方法不相同。那么,我的两个问题:

1) 为什么未绑定方法 X.method 不相同?

2) 如何使用 C API 测试它们的相等性?

我现在解决了。

1) 方法查找似乎创建了一个新对象,将 python 函数包装到一个新对象中。这就是为什么甚至

X.method is X.method

returns False.

2) PyMethod_Function(method) 可用于从方法对象中获取函数(PyObject *)。这确实实现了所需的行为:

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, "propensity");
PyObject* other_method = PyObject_GetAttrString(other_type, "propensity");
if (PyMethod_Function(self_method != PyMethod_Function(other_method))
    equal = false;
Py_XDECREF(self_method);
Py_XDECREF(other_method);

健壮的代码应该在获取它们的功能之前检查各自的属性是否确实是 PyMethods。