Define a Python class from C

I wrapped the C code for Python and it works. Module C creates a handle that I pass to Python as a PyCapsule . The API I would like to have can be done in Python, for example:

  import wrapped

 class Test (object):
    def __init __ (self, loc):
       self.handle = wrapped.new (loc)

    def foo (self, data):
       return wrapped.foo (self.handle, data)

So the question is a more cosmetic issue. Do I need to wrap the shell or can I move the code, as shown above, into C code, i.e. Export a class, not a bunch of functions?

+7
c python-c-api python-extensions
source share
2 answers

Yes, you can create your own class types in C. From the C API, the Python type / class is an instance of the PyTypeObject structure, populated accordingly for your type. The whole procedure for this is well described in the following tutorial:

https://docs.python.org/2/extending/newtypes.html

This will allow you to determine the initial kernel type, and then add data and methods to the type / class. At first, this might seem like a terrible job just to get a class implemented in C, but once you do it a few times and enjoy it, it really is not so bad.

The following is an example implementation of a test class that you define in your question.

 #include <Python.h> #include "structmember.h" typedef struct { PyObject_HEAD /* Your internal 'loc' data. */ int loc; } Test; static void MyTest_dealloc(Test* self) { self->ob_type->tp_free((PyObject*)self); } static PyObject * Test_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { Test *self; self = (Test *)type->tp_alloc(type, 0); self->loc = 0; return (PyObject *)self; } static int Test_init(Test *self, PyObject *args, PyObject *kwds) { if (! PyArg_ParseTuple(args, "i", &self->loc)) return -1; return 0; } static PyMemberDef Test_members[] = { {"loc", T_INT, offsetof(Test, loc), 0, "mytestobj loc"}, {NULL} /* Sentinel */ }; static PyObject * Test_foo(Test* self, PyObject *args) { int data; PyObject *result; if (! PyArg_ParseTuple(args, "i", &data)) { return NULL; } /* We'll just return data + loc as our result. */ result = Py_BuildValue("i", data + self->loc); return result; } static PyMethodDef Test_methods[] = { {"foo", (PyCFunction)Test_foo, METH_VARARGS, "Return input parameter added to 'loc' argument from init.", }, {NULL} /* Sentinel */ }; static PyTypeObject mytest_MyTestType = { PyObject_HEAD_INIT(NULL) 0, /*ob_size*/ "mytest.MyTest", /*tp_name*/ sizeof(Test), /*tp_basicsize*/ 0, /*tp_itemsize*/ (destructor)MyTest_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 */ 0, /*tp_call*/ 0, /*tp_str*/ 0, /*tp_getattro*/ 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,/*tp_flags*/ "MyTest objects", /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ Test_methods, /* tp_methods */ Test_members, /* tp_members */ 0, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ (initproc)Test_init,/* tp_init */ 0, /* tp_alloc */ Test_new, /* tp_new */ }; static PyMethodDef mytest_methods[] = { {NULL} /* Sentinel */ }; #ifndef PyMODINIT_FUNC /* declarations for DLL import/export */ #define PyMODINIT_FUNC void #endif PyMODINIT_FUNC initmytest(void) { PyObject* m; if (PyType_Ready(&mytest_MyTestType) < 0) return; m = Py_InitModule3("mytest", mytest_methods, "Example module that creates an extension type."); Py_INCREF(&mytest_MyTestType); PyModule_AddObject(m, "Test", (PyObject *)&mytest_MyTestType); } 

And its use with the Python interpreter:

 >>> from mytest import Test >>> t = Test(5) >>> t.foo(10) 15 
+3
source share

Maybe this is not your question. But it can be helpful.

 #include "boost/python.hpp" using namespace boost::python; int main() { Py_Initialize(); object pyFunPlxMsgWrapper = import("your_module").attr("PlxMsgWrapper"); pyFunPlxMsgWrapper(2, "string", "data"); return 0; } 
0
source share

All Articles