Defining Python class methods in C

Bryan belred1 at yahoo.com
Sat Mar 22 18:44:58 EST 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);
	Py_Initialize();

	/* 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,
NULL);
	}
	

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
  path



here is the Context object:


#include <python/Python.h>

staticforward PyTypeObject context_type;


typedef struct {
	PyObject_HEAD
	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';
	
	Py_INCREF(Py_None);
	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 {
		Py_INCREF(Py_None);
		return Py_None;
	}
}



static void context_dealloc(PyObject *self)
{
	PyObject_Del(self);
}


static PyTypeObject context_type = {
	PyObject_HEAD_INIT(NULL)
	0,
	"Context",
	sizeof(context_object),
	0,
	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
object."},
	{"get_path", context_get_path, METH_NOARGS, "Get the path"},
	{NULL, NULL, 0, NULL}
};

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);
	Py_DECREF(class_dict);
	Py_DECREF(class_name);
	Py_DECREF(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);
		Py_DECREF(func);
		Py_DECREF(method);
	}

	context_type.ob_type   = &PyType_Type;
}


thanks,

bryan




More information about the Python-list mailing list