Python 实现数值方法总是返回NotImplemented

Python 实现数值方法总是返回NotImplemented,python,python-c-api,Python,Python C Api,我正在编写一个新的扩展类型,但在设置数字运算(如加法/减法/乘法)时遇到了问题。我已经成功地设置了一些就地操作,而没有调用正常操作 例如,我有以下功能: static PyObject * MyType_Mul(PyObject *v, PyObject *w) { PyErr_SetString(PyExc_ValueError, "testing"); return NULL; } 我在数字方法中设置如下: static PyNumberMethods my_type_as

我正在编写一个新的扩展类型,但在设置数字运算(如加法/减法/乘法)时遇到了问题。我已经成功地设置了一些就地操作,而没有调用正常操作

例如,我有以下功能:

static PyObject *
MyType_Mul(PyObject *v, PyObject *w)
{
    PyErr_SetString(PyExc_ValueError, "testing");
    return NULL;
}
我在数字方法中设置如下:

static PyNumberMethods my_type_as_number = {
    0,  /* nb_add */
    0,  /* nb_sub */
    (binaryfunc)MyType_Mul,  /* nb_mul */
    ...
    0,  /* nb_in_place_add */
    0,  /* nb_in_place_sub */
    (binaryfunc)MyType_Mul,  /* nb_in_place_mul */
    ...
};
现在,当我尝试使用我的类型时,我得到了这种行为:

>>> from mytype import MyType
>>> a = MyType()
>>> a * 2
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for *: 'mytype.MyType' and 'int'
>>> 2 * a
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for *: 'int' and 'mytype.MyType'
所以,正如你所看到的,它们是完全相同的东西


发生什么事了?为什么相同的精确功能适用于就地操作员,但不适用于“正常”操作员?我还认为我可能使用了错误的插槽,但我仔细检查了它是否正确,并将其设置为
nb\u add
nb\u sub
等。不起作用。

多亏了nneonneo的评论,我明白了问题所在。基本上我忘了挂国旗了

在我给出的描述中,有一些关于这种缺失的线索:

  • 这些方法是相同的对象,但对就地操作的作用不同
  • 在评论中,我还说,例如,执行
    a*a
    将产生正确的结果,而执行
    a*不同类型的
    则不会
  • 这显然意味着解释器在执行非就地操作时,正在检查参数的类型,如果类型是
    MyType
    ,则调用my函数,否则返回
    NotImplemented

    在文档中搜索一下,很容易看出这是数值方法的默认行为

    如果参数类型不属于同一类,则假定未实现该操作

    要允许不同类型一起“操作”,您必须在
    MyType
    中设置
    Py\u TPFLAGS\u CHECKTYPES
    标志:

    static PyTypeObject MyType = {
        PyObject_HEAD_INIT(&PyType_Type)
        0,                         /*ob_size*/
        "mytype.MyType",           /*tp_name*/
        sizeof(MyTypeObject),      /*tp_basicsize*/
        0,                         /*tp_itemsize*/
        ...
        0,                         /*tp_repr*/
        &mytype_as_number,         /*tp_as_number*/
        0,                         /*tp_as_sequence*/
        ...
        Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES,/*tp_flags*/
        ...
    };
    
    设置此标志后,解释器将不会检查类型,因此您必须手动处理它们


    相反,就地操作符始终允许不同的类型。为什么会这样,我不知道。

    如果你返回一些东西而不是抛出一个异常,它会起作用吗?我尝试使用
    Py\u return\u NONE而不是异常和就地变量正确返回
    None
    ,而另一个变量返回
    NotImplemented
    (从而引发TypeError)。如果执行
    a*a
    ,它是否有效?(抱歉问20个问题:P)天哪,如果我做
    a*a
    我得到
    None
    ,而做
    a*2
    会触发错误。你明白了吗?我还是不明白为什么会有这种行为。我忘了设置
    Py\u TPFLAGS\u CHECKTYPES
    >>> a.__mul__
    <method-wrapper '__mul__' of mytype.MyType object at 0x7fc2ecc50468>
    >>> a.__imul__
    <method-wrapper '__imul__' of mytype.MyType object at 0x7fc2ecc50468>
    
    static PyTypeObject MyType = {
        PyObject_HEAD_INIT(&PyType_Type)
        0,                         /*ob_size*/
        "mytype.MyType",           /*tp_name*/
        sizeof(MyTypeObject),      /*tp_basicsize*/
        0,                         /*tp_itemsize*/
        ...
        0,                         /*tp_repr*/
        &mytype_as_number,         /*tp_as_number*/
        0,                         /*tp_as_sequence*/
        ...
        Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES,/*tp_flags*/
        ...
    };