实现数值方法总是返回NotImplemented

2024-04-16 08:19:50 发布

您现在位置:Python中文网/ 问答频道 /正文

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

例如,我有一个函数:

static PyObject *
MyType_Mul(PyObject *v, PyObject *w)
{
    PyErr_SetString(PyExc_ValueError, "testing");
    return NULL;
}

我把它设置成这样的数字方法:

^{2}$

当我试着用这种方式

>>> 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'

但如果我使用在位运算符:

>>> a *= 2
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: testing

如果我在对象上使用dir(),我可以看到__mul__和{}方法(这意味着python可以看到它们),但似乎根本没有调用它们。 使用a.__mul__(2)返回{}。在

同时:

>>> a.__mul__
<method-wrapper '__mul__' of mytype.MyType object at 0x7fc2ecc50468>
>>> a.__imul__
<method-wrapper '__imul__' of mytype.MyType object at 0x7fc2ecc50468>

所以,正如你所看到的,它们是完全一样的。在

怎么回事?为什么同一个精确的函数适用于在位运算符而不是“普通”运算符?我还认为我可能使用了错误的插槽,但是我再次检查了一下,它是正确的,并且还将其设置为nb_addnb_sub等也不起作用。在


Tags: inmoststdinline运算符callfilelast
1条回答
网友
1楼 · 发布于 2024-04-16 08:19:50

多亏了尼诺诺的评论,我明白了错在哪里。基本上我忘了设置^{}标志。在

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

  1. 这些方法是同一个对象,但它对就地操作的作用不同
  2. 在评论中,我还说,例如,做a*a会产生正确的结果,而做{}则不会。在

这显然意味着,在执行非就地操作时,解释器正在检查参数的类型,如果类型是MyType,则调用我的函数,否则返回NotImplemented。在

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

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

要允许不同类型一起“操作”,您必须在MyType中设置Py_TPFLAGS_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*/
    ...
};

设置此标志后,解释器将不会检查类型,因此您必须手动处理它们。在

相反,就地运算符始终允许不同的类型。为什么,我不知道。在

相关问题 更多 >