Implementing a "classmethod" in an extension type
Mark Franklin
mfranklin at tcsi.com
Tue Apr 1 14:54:53 EST 2003
Thanks Thomas,
The key was the DoClassMethods() call at the end of your code. Once I'd copied that over, it worked perfectly:)
void DoClassMethods(PyTypeObject *type)
{
PyObject *func;
PyObject *meth;
PyMethodDef *ml = type->tp_methods;
for (; ml->ml_name; ++ml) {
if ((ml->ml_flags & METH_CLASS) == 0)
continue;
ml->ml_flags &= ~METH_CLASS;
func = PyCFunction_New(ml, NULL);
if (!func)
return;
meth = PyObject_CallFunctionObjArgs(
(PyObject *)&PyClassMethod_Type,
func, NULL);
if (!meth)
return;
if (-1 == PyDict_SetItemString(type->tp_dict,
ml->ml_name,
meth))
return;
}
}
Mark
> -----Original Message-----
> From: Thomas Heller [mailto:theller at python.net]
> Sent: 01 April 2003 16:10
> To: python-list at python.org
> Subject: Re: Implementing a "classmethod" in an extension type
>
>
> "Mark Franklin" <mfranklin at tcsi.com> writes:
>
> > Hi,
> >
> > I've got an built-in extension type, implemented in C. I
> want to be able to implement the equivalent of a
> "classmethod" in that type.
> >
> > I thought I might be able to do something like this, which
> fairly closely mimics what you do in Python:
> >
> > PyTypeObject myType = {
> > // initialised in the usual way. It's
> tp_methods field includes a method definition for "MyMethod".......
> > };
> >
> > PyObject *method = PyObject_GetAttrString(myType, "MyMethod");
> > // method is a PyMethodDescrObject
> > PyObject *classMethod = PyClassMethod_New(method);
> > PyObject_SetAttrString(myType, "MyMethod", classMethod);
> > Py_DECREF(method);
> >
> > PyType_Ready(myType);
> >
> >
> > However, when I do this I get a TypeError exception from
> the PyObject_SetAttrString call: "can't set attributes of
> built-in/extension type 'MyType' ".
> >
> > So, how do I get the class method into the type object?
> >
> >
> > Thanks,
> > Mark
>
> In Python 2.3, there is a METH_CLASS flag. Unfortunately not in 2.2.
> Here are the relevant snippets that I use - it is from
> http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/ctypes/ctypes/s
> ource/_ctypes.c
> and it compiles with Python 2.2 as well as 2.3.
>
> HTH,
>
> Thomas
>
>
> #include "Python.h"
>
> #ifndef METH_CLASS
> #define METH_CLASS 0x0010 /* from Python 2.3 */
> #define NO_METH_CLASS
> #endif
>
> ...
>
> /*
> * If this is a real C classmethod (Python 2.3 and later),
> * it has METH_O style. So the type is in the first argument,
> * and the arg in the second.
> *
> * We fake this in Python 2.2, where METH_CLASS is not present,
> * and 'args' is a tuple containing the type as first member.
> */
> static PyObject *
> CString_from_param(PyObject *cls, PyObject *args)
> {
> PyObject *value;
>
> #ifdef NO_METH_CLASS
> PyObject *ignore;
>
> if (!PyArg_ParseTuple(args, "OO", &ignore, &value))
> return NULL;
> #else
> value = args;
> #endif
> ...
> }
>
>
> static PyMethodDef CString_methods[] = {
> #ifdef NO_METH_CLASS /* Python 2.2 */
> { "from_param", CString_from_param, METH_VARARGS | METH_CLASS,
> #else
> { "from_param", CString_from_param, METH_O | METH_CLASS,
> #endif
> from_param_doc },
> { NULL, NULL },
> };
>
>
> ...
>
> if (PyType_Ready(&CString_Type) < 0)
> return;
> #ifdef NO_METH_CLASS
> DoClassMethods(&CString_Type);
> #endif
> PyModule_AddObject(m, "c_string", (PyObject *)&CString_Type);
>
> --
> http://mail.python.org/mailman/listinfo/python-list
>
More information about the Python-list
mailing list