我正在编写functools.partial
object alternative,它累加参数,直到它们的数目足以进行调用。
我使用C API,并且我有tp_call
实现,当它被调用时,返回self或PyObject*
的修改版本。
起初,我遵循Defining New Types指南,然后意识到,我无法从PyObject *
实现返回不同的类型(MyObject*
和tp_call
)。
然后我尝试不使用struct
和MyObject*
定义,而是在PyObject_SetAttrString
中使用tp_init
,就像我们在Python中那样。但在这种情况下,我得到了AttributeError
,因为您不能在Python中的object
实例上设置任意属性。
这里我需要的是使我的tp_call
实现具有多态性,并使它能够返回MyObject
的子类PyObject
或PyObject
类型本身。
做那件事的明智方法是什么?
更新#0
这就是密码:
static PyObject *Curry_call(Curry *self, PyObject *args,
PyObject *kwargs) {
PyObject * old_args = self->args;
self->args = PySequence_Concat(self->args, args);
Py_DECREF(old_args);
if (self->kwargs == NULL && kwargs != NULL) {
self->kwargs = kwargs;
Py_INCREF(self->kwargs);
} else if (self->kwargs != NULL && kwargs != NULL) {
PyDict_Merge(self->kwargs, kwargs, 1);
}
if ((PyObject_Size(self->args) +
(self->kwargs != NULL ? PyObject_Size(self->kwargs) : 0)) >=
self->num_args) {
return PyObject_Call(self->fn, self->args, self->kwargs);
} else {
return (PyObject *)self;
}
}
更新#1
为什么我最初放弃了这个实现-因为我在随后的部分对象调用中得到了segfault。我认为这是因为从
Curry *
到PyObject*
的问题。但现在我已经通过在返回之前添加Py_INCREF(self);
来修复segfault。对我来说很奇怪。如果我按C API所有权规则返回self,我真的应该增加self吗? 最佳答案
如果您已经正确定义了MyObject
类型,那么您应该能够简单地将MyObject *
转换为PyObject *
并返回它。MyObject
的第一个成员是一个PyObject
,C允许您将指向结构的指针转换为指向结构的第一个成员的指针,反之亦然。我相信这个特性是专门允许这样的。
关于python - 如何在Python C API中实现多态?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/29575854/