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