2017-02-22 21 views
1

我對Cython擴展類型(cdef class)實施了方法__richcmp__。有些比較案例未定義(例如<),所以我曾經爲他們提出Exceptionas follows如果__richcmp__僅部分實現,是否應該引發TypeError?

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忽略。 Cython requires__richcmp__被實施,所以我沒有選擇只定義__eq____ne__。我的代碼改爲TypeError。看來,如果Python將缺少__lt__TypeError溝通,那麼我應該這樣做,以表示__lt__不存在,儘管存在整個__richcmp__,這是使用Cython的副產品,而不是設計意圖。

這個推理是否有意義?我應該提出另一種例外嗎?我在這方面是否正確地解釋了TypeError的含義?

回答

1

是的。 Cython將您的實現用作C API tp_richcompare。如果你想實現一個類型,其中只有一組有限的比較纔有意義(如==!=,但不<和朋友),直接在豐富的比較功能提高TypeError該文檔告訴你

這給了你一個相當強烈的暗示,這是正確的做法。

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

(圓點縮寫的討論主題無關線)的PyTypeObjectCPython 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; 

找到第一個摘錄或者搜索感興趣的Python的線(這裏的Function.__richcmp__簽名)的C文件,然後搜索的呼叫者的方式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__ 

有趣的是,該意見有可能表明,在未來用戶將可以實現獨立的比較方法,因此不直接遇到這個問題。

相關問題