2017-02-22 7 views
1

私は、__richcmp__をCython拡張タイプ(cdef class)に実装しました。いくつかの比較ケースは定義されていません(たとえば<)。as followsの場合はExceptionを使用しました。__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.') 

私はこのCythonクラスのインスタンスのpprintコンテナにしたいです。 pprint attempts to compareTypeErrorを除く)。私の理解ではTypeErrorとして、pprint未定義__lt__の場合、または異なるタイプのオブジェクトの場合を予想していることである(またPython docsを参照してください)。

ただし、__richcmp__です。したがって、PythonではTypeErrorが発生しません。 __richcmp__が呼び出され、Exceptionが呼び出され、それはpprintによって無視されません。実装される__richcmp__ Cython requiresは、私は唯一の__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は、最初の抜粋を見つける方法は、最初の発信者を検索し、次に関心のPythonのライン(Function.__richcmp__のここで署名)のCファイルを検索し、ことによる後

/* "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関数(このディスカッションの指針では、tp_richcompareを検索して見つけました)。

興味深いことに
# Later -- synthesize a method to split into separate ops? 
MethodSlot(richcmpfunc, "tp_richcompare", "__richcmp__", inherited=False), # Py3 checks for __hash__ 

、コメントがおそらく将来のユーザーにこのように、別々のコンパレータのメソッドを実装することはできないだろうことを示唆している:

は、私はCythonは Cython/Compiler/TypeSlots.pyから最初の抜粋を生成することを信じて、確認するために、この質問に直接遭遇する。

関連する問題