3

我在尝试实现__eq__作为 C 扩展编写的 Rect 类时遇到了麻烦。我尝试定义一个名为 的方法__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
4

2 回答 2

4

当使用 C 中定义的新类型时,您需要定义 tp_richcompare。下面是一个富比较的实现,它总是比较大于所有其他类型(除了它自己):

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,请将其添加到 type 对象,如下所示:

(richcmpfunc)&Largest_richcompare,       /* tp_richcompare */

如果您使用的是 Python 2.x,则涉及一个额外的步骤。在 Python 2.x 的生命周期中添加了丰富的比较,对于一些 Python 版本,C 扩展可以选择定义 tp_richcomare。要通知 Python 2.x 您的类型实现了丰富的比较,您需要通过 Py_TPFLAGS_HAVE_RICHCOMPARE 中的 or-ing 来修改 tp_flags。

Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_RICH_COMPARE,        /* tp_flags */
于 2012-08-19T04:21:15.723 回答
0

当你声明你的 PyTypeObject 时,有一个“丰富的比较”函数字段对应__cmp__于 python 函数 (http://docs.python.org/py3k/extending/newtypes.html#object-comparison)(在文档“非丰富”,而不是“丰富”的__eq__,__gt__等)。除了语义,它基本上提供了相同的功能,虽然我不太确定为什么__eq__不起作用......

另外,我建议任何其他编写 C 扩展类/模块的人来看看 Cython,它确实添加了一个依赖项(尽管它只是一个构建依赖项),但让编写扩展名变得不那么令人头疼。

于 2012-08-19T04:21:13.600 回答