Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how do I return objects from a C++ function with ctypes?

Tags:

c++

python

ctypes

I have two C++ classes, Container and Item, that look like:

class Item{
public:
    Item(std::string* name,int id);
    std::string* getName();
private:
    std::string* name;
    int id;
};

class Container {
public:
    Container();
    Item* getItem(int id);
private:
    std::vector<Item*> items;
};

I want to create and use Container in Python, so I wrote a C interface to compile a shared library:

extern "C" {
    Container* Container_init(){return new Container();}
    Item* Container_getItem(Container* container,int id){return container->getItem(id);}
    std::string* Item_getName(Item* item){return item->getName();}
}

and a Python wrapper:

from ctypes import *

lib = cdll.LoadLibrary(myLibPath)

class Item(object):
    def getName(self):
        return lib.Item_getName(self.obj)

class Container(object):
    def __init__(self):
        self.obj = lib.Container_init()

    def getItem(self,id):
        return lib.Container_getItem(self.obj,id)


lib.Container_getItem.restype = Item
lib.Container_getItem.argtypes = [c_void_p,c_int]

c = Container()
print c.getItem(5).getName()

When this code runs, it raises a TypeError "object() takes no parameters" at line

return lib.Container_getItem(self.obj,id)

I read about restype and argtype in the documentation but I'm obviously missing something, how can I make Container.getItem return an Item in Python?

like image 698
lelloman Avatar asked Mar 23 '23 03:03

lelloman


1 Answers

You can also use cffi.

Here's an cffi alternative:

import cffi

ffi = cffi.FFI()
ffi.cdef('''
    typedef struct _Item Item;
    typedef struct _Container Container;
    Container* Container_init();
    Item* Container_getItem(Container* container,int id);
    const char* Item_getName(Item* item);
''')

lib = ffi.dlopen(myLibPath)

class Item(object):
    def __init__(self, obj):
        self.obj = obj
    def getName(self):
        return lib.Item_getName(self.obj)

class Container(object):
    def __init__(self):
        self.obj = lib.Container_init()
    def getItem(self, id):
        return Item(lib.Container_getItem(self.obj, id))

c = Container()
print ffi.string(c.getItem(5).getName())
like image 94
falsetru Avatar answered Mar 31 '23 12:03

falsetru