Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Inheritance in Python C++ extension

Tags:

c++

python

I have c++ library that need communicate with Python plugged in modules. Communication supposes implementing by Python some callback c++ interface.

I have read already about writing extensions, but no idea how to develop inheritance.

So something about: C++:

class Broadcast
{
   void set(Listener *){...
}

class Listener
{
    void notify(Broadcast* owner) = 0;
}

I need something like in Python:

class ListenerImpl(Listener):
    ...
    def notify(self, owner):
        ...

Note, I don't want use Boost.

like image 460
Dewfy Avatar asked Feb 04 '10 15:02

Dewfy


Video Answer


2 Answers

Since I had to implement single inheritance as part of the Python C-API in a project of mine, I built a short example here. I marked the important statements in the code.

The trick is to inherit the base struct in the top of the subclass struct (leave out the PyObject_HEAD statement).

/* OBJECT */
typedef struct {
      MyPy_BaseClass super; // <----- PUTTING THIS FIRST INHERITS THE BASE PYTHON CLASS!!!
      // Own variables:
      // e.g int x = 0;
} MyPy_InheritanceClass;

Also dont forget to give the base type to the subclass type. There is a flag for it (see /* tp_base */).

  static PyTypeObject MyPy_InheritanceClass_Type = {
    PyVarObject_HEAD_INIT(NULL, 0)
    "MyPy_InheritanceClass",          /* tp_name */
    sizeof(MyPy_InheritanceClass),    /* tp_basicsize */
    0,                         /* tp_itemsize */
    (destructor)MyPy_InheritanceClass_dealloc, /* tp_dealloc */
    0,                         /* tp_print */
    0,                         /* tp_getattr */
    0,                         /* tp_setattr */
    0,                         /* tp_reserved */
    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 */ 
    "MyPy_InheritanceClass",   /* tp_doc */
    0,                         /* tp_traverse */
    0,                         /* tp_clear */
    0,                         /* tp_richcompare */
    0,                         /* tp_weaklistoffset */
    0,                         /* tp_iter */
    0,                         /* tp_iternext */
    MyPy_InheritanceClass_methods,    /* tp_methods */
    0,                         /* tp_members */
    0,                         /* tp_getset */
    &MyPy_BaseClass_Type,      /* tp_base */ // <------ GIVE THE BASE_CLASS TYPE
    0,                         /* tp_dict */
    0,                         /* tp_descr_get */
    0,                         /* tp_descr_set */
    0,                         /* tp_dictoffset */
    (initproc) MyPy_InheritanceClass_init, /* tp_init */
    0,                         /* tp_alloc */
    MyPy_InheritanceClass_new, /* tp_new */
};
like image 58
codie Avatar answered Sep 23 '22 19:09

codie


Writing Python types in C that are inheritable is explained in PEP 253. It's not all that different from writing a normal builtin type as explained in the Extending/Embedding guide but you have to do certain things, like attribute access, through the Python API instead of accessing anything directly.

Exposing the Python subclasses back to C++ code is a little more tedious. The Python classes won't be C++ subclasses, so you need a C++ wrapper class (that does inherit from Listener) that contains a PyObject* for the Python subclass instance, and that has a notify method that translates the arguments to Python objects, calls the notify method of the PyObject* (using, e.g., PyObject_CallMethod), translates the result back to C++ types, and returns.

like image 45
Thomas Wouters Avatar answered Sep 23 '22 19:09

Thomas Wouters