Hi all, I'm still trying to find a simple way to implement a method (but not the full class) in C. Suggestions I have recived so far are good, but seem to be over the top for such a (seemingly) simple problem. I came up with the idea of implementing the class in Python, and just setting the method after the actual class definition. See example below. The "py_method" is added to the class later on, and it seems to become a proper method of the class (and its instances) just as if it had been defined inside the class itself. Of course it also has access to its "self" argument.
If I do the same thing with a method implemented in the external module "cmethod", and I call that method on an instance, it gets passed a NULL pointer as its "self" argument and so has no access to the instance's "data" attribute. I found a workaround using a wrapper method which calls a C function, passing the instance as a separate argument. It works, and I cannot see any disadvantage. It's just not as elegant as I'd like it to be, and I don't understand WHY the C "method" doesn't receive a pointer to the Python instance. Maybe somebody can clarify. Here's what happens when I build, install and run the minimal example below: rl@dc:~/c/cwsf/python_module$ python test.py py_method(): <__main__.Test instance at 0xb71f5a2c> c_method(): self at (nil) c_function(): self at (nil), instance at 0xb71f5a2c <__main__.Test instance at 0xb71f5a2c> 'Some data' c_function(): self at (nil), instance at 0xb71f5a2c <__main__.Test instance at 0xb71f5a2c> 'New Data' rl@dc:~/c/cwsf/python_module$ Minimal example files: ========================== test.py =================================== import cmethod class Test(): def __init__(self): self.data = "Some data" def wrapper(self): return cmethod.c_function(self) def py_method(self): print "py_method(): %s" % repr(self) # add methods to the class "after the fact" Test.py_method = py_method Test.c_method = cmethod.c_method foo = Test() foo.py_method() # works as expected foo.c_method() # is passed NULL in its self argument, why? foo.wrapper() # works fine, updates "data" attribute foo.wrapper() # works fine, sees updated "data" attribute ==================== cmethod.c ======================================= #include <Python.h> #include <stdio.h> static PyObject *c_method(PyObject *self, PyObject *args) { (void) args; /* not used */ fprintf(stderr, "c_method(): self at %p\n", (void*) self); /* always prints 0x0 */ Py_INCREF(Py_None); return Py_None; } static PyObject *c_function(PyObject *self, PyObject *args) { PyObject *instance; PyObject *o; /* Retrieve instance from wrapper through argument tuple: WORKS */ PyArg_UnpackTuple(args, "c_function", 1, 1, &instance); fprintf(stderr, "c_function(): self at %p, instance at %p\n", (void*) self, (void*) instance); PyObject_Print(instance, stderr, 0); fputc('\n', stderr); /* Get and set attributes of instance: WORKS */ o = PyObject_GetAttrString(instance, "data"); PyObject_Print(o, stderr, 0); fputc('\n', stderr); PyObject_SetAttrString(instance, "data", PyString_FromString("New Data")); /* Side question: Do I have to DECREF "o"? */ Py_INCREF(Py_None); return Py_None; } static PyMethodDef methods[] = { {"c_method", c_method, METH_VARARGS, "I want to be a class method"}, {"c_function", c_function, METH_VARARGS, "I am a function"}, {NULL, NULL, 0, NULL} }; PyMODINIT_FUNC initcmethod(void) { (void) Py_InitModule("cmethod", methods); } ======================== setup_cmethod.py =========================== from distutils.core import setup, Extension module1 = Extension('cmethod', sources = ['cmethod.c']) setup (name = 'cmethod', version = '0.1', description = 'struggling to implement a class method in C', ext_modules = [module1]) robert -- https://mail.python.org/mailman/listinfo/python-list