473,386 Members | 1,969 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,386 software developers and data experts.

Defining *class* methods on C code

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
12 1906
> 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
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
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
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
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
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
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
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
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
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
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
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 thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

7
by: Harry Pehkonen | last post by:
I have been defining new class methods when I'm trying to simplify some code. But I'm thinking I should just define functions within that method because they aren't useful from the outside anyway....
7
by: Bob Rock | last post by:
Hello, this may seem a strange question, but is there a way of being able to call methods of a class through an array of that class when not referencing a specific object in the array. In other...
5
by: Dale | last post by:
Is it possible to declare a method of an interface as static? For instance, can I create an interface that defines a static method and 2 instance methods?
2
by: lcaamano | last post by:
We have a tracing decorator that automatically logs enter/exits to/from functions and methods and it also figures out by itself the function call arguments values and the class or module the...
26
by: Cliff Williams | last post by:
Can someone explain the pros/cons of these different ways of creating a class? // 1 function myclass() { this.foo1 = function() {...} } // 2a
9
by: Nick Maclaren | last post by:
I am defining a class, and I need to refer to that class when setting up its static data - don't ask - like this: Class weeble : wumpus = brinjal(weeble) Does anyone know how I can achieve...
2
by: =?Utf-8?B?Z2FkeWE=?= | last post by:
I use one of 2 arrays dependent on the country. Rather than say: if exchangeID = 1 then dim myPlaceBets() as As UK.exchange.PlaceBets many statements myPlaceBetsReq.bets = myPlaceBets else...
0
by: taylorcarr | last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.