如何比较 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。
我正在尝试移植一些 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。