我在尝试为我作为C扩展编写的Rect类实现__eq__
时遇到了麻烦。我尝试定义一个名为__eq__
的方法,但Python似乎会覆盖它。
static PyObject *
Rect___eq__(Rect *self, PyObject *other)
{
Rect *rect = (Rect *) other;
if (self->x != rect->x || self->y != rect->y ||
self->width != rect->width || self->height != rect->height) {
Py_RETURN_FALSE;
} else {
Py_RETURN_TRUE;
}
}
static PyMethodDef Rect_methods[] = {
{"__eq__", (PyCFunction)Rect___eq__, METH_VARARGS,
"Compare Rects" },
{NULL} /* Sentinel */
};
似乎无论我做什么,Python默认为“是”行为:
>>> a = Rect(1, 2, 3, 4)
>>> b = Rect(1, 2, 3, 4)
>>> a == b
False
>>> a == a
True
答案 0 :(得分:4)
使用C中定义的新类型时,需要定义tp_richcompare。下面是一个类型的丰富比较实现,它总是比所有其他类型(自身除外)大: p>
static PyObject *
Largest_richcompare(PyObject *self, PyObject *other, int op)
{
PyObject *result = NULL;
if (UndefinedObject_Check(other)) {
result = Py_NotImplemented;
}
else {
switch (op) {
case Py_LT:
result = Py_False;
break;
case Py_LE:
result = (LargestObject_Check(other)) ? Py_True : Py_False;
break;
case Py_EQ:
result = (LargestObject_Check(other)) ? Py_True : Py_False;
break;
case Py_NE:
result = (LargestObject_Check(other)) ? Py_False : Py_True;
break;
case Py_GT:
result = (LargestObject_Check(other)) ? Py_False : Py_True;
break;
case Py_GE:
result = Py_True;
break;
}
}
Py_XINCREF(result);
return result;
}
如果您使用的是Python 3.x,则将其添加到类型对象中,如下所示:
(richcmpfunc)&Largest_richcompare, /* tp_richcompare */
如果您使用的是Python 2.x,则需要执行额外的步骤。在Python 2.x的生命周期中添加了丰富的比较,对于一些Python版本,C扩展可以选择定义tp_richcomare。要通知Python 2.x您的类型实现了丰富的比较,您需要通过或者在Py_TPFLAGS_HAVE_RICHCOMPARE中修改tp_flags。
Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_RICH_COMPARE, /* tp_flags */
答案 1 :(得分:0)
当您声明PyTypeObject时,有一个字段用于"丰富的比较"函数对应于python函数上的__cmp__
(http://docs.python.org/py3k/extending/newtypes.html#object-comparison)(在文档中调用" nonrich"而不是__eq__
,__gt__
等,这些都是"富裕")。除了语义,它基本上提供相同的功能,但我不太清楚为什么__eq__
不起作用...
除此之外,我建议其他人编写C扩展类/模块来看看Cython,它确实添加了一个依赖项(虽然它只是一个构建依赖项)但是使编写扩展很多少了头疼。