By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
438,427 Members | 1,379 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 438,427 IT Pros & Developers. It's quick & easy.

Defining *class* methods on C code

P: n/a
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)

Thanks,

Thomas
Jul 18 '05 #1
Share this Question
Share on Google+
12 Replies


P: n/a
> 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)


Try METH_STATIC as flag for PyMethodDef.

--

Regards,

Diez B. Roggisch
Jul 18 '05 #2

P: n/a
Thomas Heller <th*****@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).

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

Cheers,
mwh

-- Well, as an American citizen I hope that the EU tells the MPAA
and RIAA to shove it where the Sun don't shine.

Actually they already did. Only first they bent over and dropped
their trousers. -- Shmuel (Seymour J.) Metz & Toni Lassila, asr
Jul 18 '05 #3

P: n/a
Michael Hudson <mw*@python.net> writes:
Thomas Heller <th*****@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
Jul 18 '05 #4

P: n/a
Thomas Heller <th*****@python.net> writes:

[followup to myself, I found it]
Michael Hudson <mw*@python.net> writes:
Thomas Heller <th*****@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):

[snipped non-working code]

I have to call PyDescr_NewClassMethodType:

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

for (; ml->ml_name; ++ml) {
meth = PyDescr_NewClassMethod(type, ml);
if (!meth)
return NULL;
if (-1 == PyDict_SetItemString(type->tp_dict,
ml->ml_name,
meth))
return NULL;
}
}
I know that there are refcount leaks in this snippet, but that's not the
point.


Thomas
Jul 18 '05 #5

P: n/a
Thomas Heller <th*****@python.net> writes:
Michael Hudson <mw*@python.net> writes:
Thomas Heller <th*****@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
Jul 18 '05 #6

P: n/a
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?


Yes, that works. But it's not in Python 2.2, which is required ;-(

Thanks,

Thomas
Jul 18 '05 #7

P: n/a
On Fri, 6 Feb 2004, Thomas Heller wrote:
I have to call PyDescr_NewClassMethodType:


File a doc bug? I can't find this in the 2.3.3 docs at all...

--
Andrew I MacIntyre "These thoughts are mine alone..."
E-mail: an*****@bullseye.apana.org.au (pref) | Snail: PO Box 370
an*****@pcug.org.au (alt) | Belconnen ACT 2616
Web: http://www.andymac.org/ | Australia

Jul 18 '05 #8

P: n/a
Thomas Heller <th*****@python.net> writes:
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?


Yes, that works. But it's not in Python 2.2, which is required ;-(


Arghl. I guess you can just steal the relavent code... wasn't it your
patch in the first place that implemented all this?

Cheers,
mwh

--
$ head -n 2 src/bash/bash-2.04/unwind_prot.c
/* I can't stand it anymore! Please can't we just write the
whole Unix system in lisp or something? */
-- spotted by Rich van der Hoff
Jul 18 '05 #9

P: n/a
Michael Hudson <mw*@python.net> writes:
Thomas Heller <th*****@python.net> writes:
>> 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?
>


Yes, that works. But it's not in Python 2.2, which is required ;-(


Arghl. I guess you can just steal the relavent code... wasn't it your
patch in the first place that implemented all this?


No, it was my feature request. IIRC, it was implemented by Fred Drake.

Thomas
Jul 18 '05 #10

P: n/a
Thomas Heller <th*****@python.net> writes:
Michael Hudson <mw*@python.net> writes:
Thomas Heller <th*****@python.net> writes:
>> 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?
>

Yes, that works. But it's not in Python 2.2, which is required ;-(


Arghl. I guess you can just steal the relavent code... wasn't it your
patch in the first place that implemented all this?


No, it was my feature request. IIRC, it was implemented by Fred Drake.


Guess I'm getting old. It *was* my patch ;-)

Thomas
Jul 18 '05 #11

P: n/a
Andrew MacIntyre <an*****@bullseye.apana.org.au> writes:
On Fri, 6 Feb 2004, Thomas Heller wrote:
I have to call PyDescr_NewClassMethodType:


File a doc bug? I can't find this in the 2.3.3 docs at all...


I've checked it in directly, but only the function prototype.

Thomas
Jul 18 '05 #12

P: n/a
Thomas Heller <th*****@python.net> writes:
Thomas Heller <th*****@python.net> writes:
Michael Hudson <mw*@python.net> writes:
Arghl. I guess you can just steal the relavent code... wasn't it your
patch in the first place that implemented all this?


No, it was my feature request. IIRC, it was implemented by Fred Drake.


Guess I'm getting old. It *was* my patch ;-)


:-)

Cheers,
mwh

--
at any rate, I'm satisfied that not only do they know which end of
the pointy thing to hold, but where to poke it for maximum effect.
-- Eric The Read, asr, on google.com
Jul 18 '05 #13

This discussion thread is closed

Replies have been disabled for this discussion.