I'm writing functools.partial
object alternative, that accumulates arguments until their number become sufficient to make a call.
I use C API and I have tp_call
implementation which when its called, returns modified version of self or PyObject*
.
At first I followed Defining New Types guide and then realized, that I just can't return different types (PyObject *
and MyObject*
) from tp_call
implementation.
Then I tried to not use struct
with MyObject*
definition and use PyObject_SetAttrString
in tp_init
instead, just like we do that in Python. But in that case I got AttributeError
, because you can't set arbitrary attributes on object
instances in Python.
What I need here is to make my tp_call
implementation polymorphic, and make it able to return either MyObject
which is subclass of PyObject
, or PyObject
type itself.
What is the sane way to do that?
UPDATE #0
That's the code:
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;
}
}
UPDATE #1
Why I initially abandoned this implementation - because I get segfault with it on subsequent calls of partial object. I thought that It happens because of casting Curry *
to PyObject*
issues. But now I have fixed the segfault by adding Py_INCREF(self);
before return (PyObject *)self;
. Very strange to me. Should I really INCREF self if I return it by C API ownership rules?