I was reading through the file methodobject.c, because I'm trying to learn about making C extensions for Python, when I saw the following code snippet:
PyObject *
PyCFunction_Call(PyObject *func, PyObject *arg, PyObject *kw)
{
PyCFunctionObject* f = (PyCFunctionObject*)func;
PyCFunction meth = PyCFunction_GET_FUNCTION(func);
PyObject *self = PyCFunction_GET_SELF(func);
Py_ssize_t size;
switch (PyCFunction_GET_FLAGS(func) & ~(METH_CLASS | METH_STATIC | METH_COEXIST)) {
case METH_VARARGS:
if (kw == NULL || PyDict_Size(kw) == 0)
return (*meth)(self, arg);
break;
The more I look at
return (*meth)(self, arg);
the more I realize I don't understand it. I think it's returning a pointer to meth, which is a function that takes self (a locally declared pointer) and arg (a pointer passed externally into PyCFunctionCall). However, since it looks to me as though meth & self are allocated on the stack, once PyCFunctionCall exits, they will be freed, which will cause problems for whatever variables they are passed to.
What am I missing here?
It's returning the return value of meth(self, arg)
, not meth
itself. Note that it's derferencing the pointer with (*meth)
, then passing in self
and arg
to the function at that location.
So meth(self, arg)
will be completely evaluated before the return
happens, and no stack variables will be returned.
Edit: when I say meth(self, arg)
, I mean the_function_pointed_to_by_meth(self, arg)
.