Defining *class* methods on C code

Thomas Heller theller at python.net
Fri Feb 6 16:31:46 CET 2004


Michael Hudson <mwh at python.net> writes:

> Thomas Heller <theller at python.net> writes:
>
>> I once knew how to do it, but I cannot find or remember it anymore:
>> 
>> How can I attach *class* methods to a type in C code, when I have a
>> function
>> 
>> PyObject *func(PyObject *type, PyObject *arg);
>> 
>> with the METH_O calling convention?  The type is already created, I
>> cannot insert it into the tp_methods array anymore.
>> 
>> Something like this:
>> 
>> class X(object):
>>     pass
>> 
>> def func(cls, arg):
>>     ....
>> 
>> X.func = classmethod(func)
>
> Just stuff it into tp_dict?  You'll need to make the method object
> yourself, but that's easy.
>
> I think you probably have to hope that the name of the class method
> isn't a special method name (you'd want to call
> typeobject.c:update_slots then, but I don't think you can arrange for
> that to happen from outside typeobject.c as all the juicy symbols are
> static).

No special names.  Here's the code:

static PyObject *my_method(PyObject *self, PyObject *arg)
{
	Py_INCREF(arg);
	return arg;
}

static PyMethodDef my_methods[] = {
	{ "my_method", my_method, METH_O },
	{ NULL, NULL },
};

and then ('type' is the type where I want to create the class method on):

	if (somecondition) {
		PyObject *func;
		PyObject *meth;
		PyMethodDef *ml = my_methods;

		for (; ml->ml_name; ++ml) {
			func = PyCFunction_New(ml, NULL);
			if (!func)
				return NULL;
			meth = PyClassMethod_New(func);
			if (!meth)
				return NULL;
			if (-1 == PyDict_SetItemString(result->tp_dict,
						       ml->ml_name,
						       meth))
				return NULL;
		}
	}

I know that there are refcount leaks in this snippet, but that's not the
point.

Trying out the method:

c:\sf\ctypes>py23 -c "from ctypes import *; print c_int.my_method()"
<class 'ctypes.c_int'>

c:\sf\ctypes>py23 -c "from ctypes import *; print c_int.my_method(0)"
Traceback (most recent call last):
  File "<string>", line 1, in ?
TypeError: my_method() takes exactly one argument (2 given)
c:\sf\ctypes>

Works *nearly*, but I would have expected that the method accepts one
parameter, pass it as 'arg' to the C function, plus the type itself as
'self'.

> Or just stick TP_HEAPTYPE into tp_flags, use PyObject_SetAttr and take
> TP_HEAPTYPE out again (that's very sick, though).

Um, why that?

Thanks,

Thomas



More information about the Python-list mailing list