我为Cython扩展类型(__richcmp__
)实现了方法cdef class
。某些比较案例未定义(例如<
),因此我曾经为它们as follows提出Exception
。
def __richcmp__(Function self, Function other, op):
if other is None:
eq = False
else:
# guard against mixing managers
assert self.manager == other.manager
eq = (self.node == other.node)
if op == 2:
return eq
elif op == 3:
return not eq
else:
raise TypeError('Only `__eq__` and `__ne__` defined.')
我想要pprint
此Cython类的实例容器。 pprint
attempts to compare他们,TypeError
除外。我的理解是,TypeError
,pprint
预测未定义__lt__
的情况,或不同类型对象的情况(另请参阅Python docs)。
但是,__richcmp__
已实现,因此Python不会引发TypeError
。它会调用__richcmp__
,我会引发Exception
,pprint
不会忽略它。 __richcmp__
实施__eq__
的Cython requires,因此我无法仅定义__ne__
和TypeError
。
我将代码更改为引发__lt__
。似乎如果Python通过TypeError
传达__lt__
的缺失,那么我应该这样做,以表示__richcmp__
不存在,尽管存在整个TypeError
System.getProperty
1}},这是使用Cython的副产品,而不是设计意图。
这种推理有意义吗?我应该提出另一种例外吗?在这种情况下,我是否正确解释了System.getenv
的含义?
答案 0 :(得分:1)
是。 Cython将您的实现用作C API tp_richcompare
。该文档告诉你
如果你想实现一种只有一组有限的比较有意义的类型(例如
==
和!=
,而不是<
和朋友),直接提升{{1在丰富的比较函数中。
这给了你一个相当强烈的暗示,这是正确的事情。
答案 1 :(得分:0)
@DavidW提供了非常精确和有用的答案,谢谢。它指出了如何处理类似的未来问题:通过查看生成的C代码。我发布这个答案作为后人的免费信息。
在生成的cudd.c
文件中搜索,我们找到了类签名:
static PyTypeObject __pyx_type_2dd_4cudd_Function = {
PyVarObject_HEAD_INIT(0, 0)
"dd.cudd.Function", /*tp_name*/
sizeof(struct __pyx_obj_2dd_4cudd_Function), /*tp_basicsize*/
0, /*tp_itemsize*/
...
...
__pyx_pw_2dd_4cudd_8Function_13__richcmp__, /*tp_richcompare*/
...
...
#if PY_VERSION_HEX >= 0x030400a1
0, /*tp_finalize*/
#endif
};
(点的缩写与我们的讨论无关。)PyTypeObject
由CPython C API定义。函数__pyx_pw_2dd
稍后定义
/* "dd/cudd.pyx":1556
* return Cudd_DagSize(self.node)
*
* def __richcmp__(Function self, Function other, op): # <<<<<<<<<<<<<<
* if other is None:
* eq = False
*/
/* Python wrapper */
static PyObject *__pyx_pw_2dd_4cudd_8Function_13__richcmp__(PyObject *__pyx_v_self, PyObject *__pyx_v_other, int __pyx_arg_op); /*proto*/
static PyObject *__pyx_pw_2dd_4cudd_8Function_13__richcmp__(PyObject *__pyx_v_self, PyObject *__pyx_v_other, int __pyx_arg_op) {
PyObject *__pyx_v_op = 0;
PyObject *__pyx_r = 0;
找到第一个摘录的方法是首先在C文件中搜索感兴趣的Python行(这里是Function.__richcmp__
的签名),然后搜索C函数的调用者(尽管在此讨论的指导下) ,我通过搜索tp_richcompare
)找到了它们。
为了确认,我相信Cython会从Cython/Compiler/TypeSlots.py生成第一个摘录:
# Later -- synthesize a method to split into separate ops?
MethodSlot(richcmpfunc, "tp_richcompare", "__richcmp__", inherited=False), # Py3 checks for __hash__
有趣的是,那里的评论或许表明,未来用户将能够实施单独的比较方法,因此不会直接遇到这个问题。