如何使用 ctypes 从C++函数返回对象

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

本文关键字:函数 返回 对象 C++ 何使用 ctypes      更新时间:2023-10-16

我有两个C++类,容器和项,如下所示:

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;
};

我想在 Python 中创建和使用 Container,所以我写了一个 C 接口来编译一个共享库:

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();}
}

和一个 Python 包装器:

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()

当此代码运行时,它会在行中引发一个 TypeError "object() 不带任何参数"

return lib.Container_getItem(self.obj,id)

我在文档中阅读了有关 restype 和 argtype 的信息,但我显然缺少一些东西,如何使Container.getItem在 Python 中返回项目?

按如下方式替换Item_getName以返回char *而不是string *

const char* Item_getName(Item* item) { return item->getName()->c_str(); }

Item类缺少__init__。更改如下(这是TypeError的原因):

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

并将以下内容添加到 Python 脚本(在调用getName方法之前)以正确获取名称:

lib.Item_getName.restype = c_char_p
lib.Item_getName.argtypes = ()

然后,你会得到你想要的。

您也可以使用 cffi .

这是一个 cffi 替代方案:

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())