Implementing a "classmethod" in an extension type
Thomas Heller
theller at python.net
Tue Apr 1 10:09:55 EST 2003
"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/source/_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);
More information about the Python-list
mailing list