Defining *class* methods on C code
Michael Hudson
mwh at python.net
Fri Feb 6 10:47:12 EST 2004
Thomas Heller <theller at python.net> writes:
> 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);
How about "meth = PyDescr_NewClassMethod(result, ml);" here?
> 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'.
Oh... I wouldn't have :-)
> > 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?
Well, if "my_method" was spelt "__add__", say, you'd want to call
typeobject.c:update_slots() to get the function into the
tp_as_number.nb_add fields of the type and all the subclasses. The
hack I outline is one way of doing that.
Cheers,
mwh
--
Every now and then, Google doesn't throw up what I need so I start
checking Altavista, Yahoo, etc. In almost every single case, I am
brutally reminded why I use Google in the first place.
-- John Riddoch, asr
More information about the Python-list
mailing list