Defining Python class methods in C

Bryan belred1 at
Sun Mar 23 00:44:58 CET 2003

thanks alex for your help so far.  i'm very close to getting this
working the way i want to.  but i'm still having trouble getting the
callback from the python script to the c code to work.  there must be
some fundamental part i'm not understanding.  here is the c code that
instatiates a Context class and setting a context value in __init__. 
this part is now working.  after the Context object is created, it's
passed to start.  start is successfully called and can see that the
parameter being passed in is a Context instance.  what's not working
is the callback into the Context class.

here is the c-code creating context.Context and calling start:
	PyImport_AppendInittab("context", initcontext);

	/* create a context object */

	py_mod_context = PyImport_ImportModule("context");
	if (!py_mod_context) goto clean_exit;

	py_cls_Context = PyObject_GetAttrString(py_mod_context, "Context");
	if (!py_cls_Context) goto clean_exit;

	sprintf(addr, "%p", ctx);
	py_tuple_addr = Py_BuildValue("(s)", addr);
	if (!py_tuple_addr) goto clean_exit;

	py_obj_Context = PyObject_CallObject(py_cls_Context, py_tuple_addr);
	if (!py_obj_Context) goto clean_exit;

	/* call start */

	py_call_start = PyObject_GetAttrString(py_mod_provider, "start");
	if (py_call_start && PyCallable_Check(py_call_start)) {
	    PyObject_CallFunctionObjArgs(py_call_start, py_obj_Context,

here's the python script that's being called.  i am not importing the
context module in the script.  this is an intentional part of the
design.  but maybe i really do need to import the context module.

  def start(ctx):
        print 'context', ctx
	print 'doc', ctx.__doc__, 'end doc'
	print 'path', ctx.get_path(), 'end path'

here is the output from start.  notice the ?, no doc string, no path
string including the 'end path' string.  i'm assuming get_path wasn't
found and an attribute exception occured.  also, my breakpoint never
stopped in the get_path callback method.  why does python show a ?. 
why doesn't it know that it's from the context module?

  context <?.Context instance at 0x00AE7D08>
  doc None end doc

here is the Context object:

#include <python/Python.h>

staticforward PyTypeObject context_type;

typedef struct {
	char context[64];
} context_object;

static PyObject* context_init(PyObject *self, PyObject *args)
	context_object *context_obj;
	PyObject       *type;
	char           *s = NULL;

	if (!PyArg_ParseTuple(args, "Os", &type, &s)) return NULL;
	context_obj = PyObject_New(context_object, &context_type);
	strncpy(context_obj->context, s, sizeof(context_obj->context));
        context_obj->context[sizeof(context_obj->context)-1] = '\0';
	return Py_None;

static PyObject* context_get_path(PyObject *self, PyObject *args)
	context_object           *context_obj = (context_object*)self;
	PyObject                 *py_str_path = NULL;

	if (context_obj) {
	  /* not a real path yet,
             just pass back the string internal context string */
	  py_str_path = PyString_FromString(context_obj->context);	

	if (py_str_path) {
		return py_str_path;
	else {
		return Py_None;

static void context_dealloc(PyObject *self)

static PyTypeObject context_type = {
	context_dealloc,  /* tp_dealloc     */
	0,                /* tp_print       */
	0,                /* tp_getattr     */
	0,                /* tp_setattr     */
	0,                /* tp_compare     */
	0,                /* tp_repr        */
	0,                /* tp_as_number   */
	0,                /* tp_as_sequence */
	0,                /* tp_as_mapping  */
	0                 /* tp_hash        */

static PyMethodDef context_methods[] = {
	{"__init__", context_init, METH_VARARGS, "Create a new context
	{"get_path", context_get_path, METH_NOARGS, "Get the path"},

static PyMethodDef module_methods[] = { {NULL, NULL, 0, NULL } };

void initcontext(void)
	PyMethodDef *def;

	/* create a context object */
	PyObject *module       = Py_InitModule("context", module_methods);
	PyObject *module_dict  = PyModule_GetDict(module);
	PyObject *class_dict   = PyDict_New();
	PyObject *class_name   = PyString_FromString("Context");		
	PyObject *class_obj    = PyClass_New(NULL, class_dict, class_name);
	PyDict_SetItemString(module_dict, "Context", class_obj);

	/* add methods to class */
	for (def = context_methods; def->ml_name != NULL; def++) {
		PyObject *func   = PyCFunction_New(def, NULL);
		PyObject *method = PyMethod_New(func, NULL, class_obj);
		PyDict_SetItemString(class_dict, def->ml_name, method);

	context_type.ob_type   = &PyType_Type;



More information about the Python-list mailing list