13

I wrapped some C code for Python and it works. The C module creates a handle, which I pass to Python as PyCapsule. The API I would like to have can be made in Python like:

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 more a cosmetic issue. Do I have to wrap the wrapper, or can I move code like shown above into the C code, i.e. export a class instead of a bunch of functions?

2 Answers 2

13

Yes, you can create your own class types in C. From the C API a Python type/class is an instance of the PyTypeObject structure filled in appropriately for your type. The whole procedure for doing this is outlined nicely in the following tutorial:

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

This will walk you through defining the initial core type and then adding data and methods to the type/class. At first it may seem like an awful lot of work just to get a class implemented in C, but once you do it a few times and get comfortable with it, it's really not so bad.

Here is a bare bones implementation of the Test class 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 usage from the Python interpreter:

>>> from mytest import Test
>>> t = Test(5)
>>> t.foo(10)
15
Sign up to request clarification or add additional context in comments.

1 Comment

This is now outdated. See stackoverflow.com/a/43622454/515212
-1

May be it's not your question ans. 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;
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.