![](/img/trans.png)
[英]Calling a C++ function from python, using cython, with cythonize
[英]Using data in Python code from C++ using Cython
我正在尝试使用Cython从我的Python代码中的C ++代码获取列表。
这是我的标头(例如h):
namespace c
{
class C {
int id;
public:
C(int id) {
this->id = id;
}
int getId();
};
typedef std::vector<C> CList;
}
和我的源文件(ex.cpp):
namespace c
{
int C::getId() {
return this->id;
}
CList getlist(int t) {
CList list;
for (int i = 0; i < t; ++i) {
C c(i);
list.push_back(c);
}
return list;
}
}
所以在我的Python代码中,我想像这样遍历CList:
import exapi
for i in exapi.take_list():
print i
# OR
print i.get_id()
在.pyx文件(exapi.pyx)中,我试图创建Cython扩展名来处理C ++对象:
cdef extern from "ex.h" namespace "c":
cdef cppclass C:
C(int) except +
int getId()
cdef cppclass CList:
pass
cdef CList getlist(int)
cdef class PY_C:
pass
cdef class PY_CList:
pass
def take_list():
return getlist(10) # I know this is wrong
我应该在PY_C和PY_Clist中添加哪些转发方法和功能,以使python代码正常工作?
我读了Cython中的Using C ++ ,但是在Cython代码中创建了新对象,但就我而言,我需要使用在C ++端创建的对象。
尝试解决这个问题时,我重写了一些示例,但是原则上您给的与我给的没有区别。
我也更改了一些名称,因为示例名称对我来说太短了;)。
cobject.hpp
#include <vector>
namespace cobject {
class CObject {
int id;
public:
CObject(int id): id(id) {}
int getId();
};
typedef std::vector<CObject> CObjectList;
CObjectList getlist(int t);
}
cobject.cpp
#include "cobject.hpp"
namespace cobject {
int CObject::getId() {
return this->id;
}
CObjectList getlist(int t) {
CObjectList list;
for (int i = 0; i < t; ++i) {
list.push_back(CObject(i));
}
return list;
}
}
这些并没有什么不同。
我想使用pyximport
,但是要在C ++中使用它,您需要一个特殊的文件:
cobject_api.pyxbld
import os
from distutils.extension import Extension
dirname = os.path.dirname(__file__)
def make_ext(modname, pyxfilename):
return Extension(
name=modname,
sources=[pyxfilename, "cobject.cpp"],
language="c++",
include_dirs=[dirname]
)
然后是魔术:
cython_api.pyx
from cython.operator cimport dereference as deref
cdef extern from "cobject.hpp" namespace "cobject":
cdef cppclass CObject:
CObject(int) except +
int getId()
cdef cppclass CObjectList:
CObject &at(size_t)
size_t size()
cdef CObjectList getlist(int)
# Cython wrappers
cdef class PyCObject:
cdef CObject *wrapped
cdef object keepalive
def __cinit__(self, keepalive):
self.keepalive = keepalive
property id:
def __get__(self):
return self.wrapped.getId()
def __repr__(self):
return "PyCObject({})".format(self.id)
cdef class PyCObjectList:
cdef CObjectList wrapped
def __iter__(self):
cdef PyCObject pycobject
cdef size_t idx = 0
while idx < self.wrapped.size():
pycobject = PyCObject(self)
pycobject.wrapped = &self.wrapped.at(idx)
yield pycobject
idx += 1
def take_list():
cdef PyCObjectList pycobjectlist = PyCObjectList()
pycobjectlist.wrapped = getlist(10)
return pycobjectlist
运行方式如下:
main.py
import pyximport
pyximport.install()
import cobject_api
for i in cobject_api.take_list():
print("{} has id {}".format(i, i.id))
这个想法是您的包装器类拥有数据的所有权。 由于getlist
是按值返回的,因此您必须对其进行复制,但是其他对象包装器可以使用指针。
与其使用CObjectList
类型,还不如使用预包装的矢量类并对其进行迭代。 但是,除非您确实使用间接指针将所有内容保留在堆上,否则将它们包装起来不是很好。
这是因为您不能轻易地指向要保留在堆栈中的内容,而Cython如果想要与Python的垃圾收集器配合使用,则需要指向这些内容。 这就解释了代码中的keepalive
变量的用途:与Python中删除向量不会影响其元素的方式不同,而在C ++中,删除向量不会影响其元素。 使用指针向量,可以缓解这些问题。
另请参阅此链接上的另一个问题。 提出了一些相同的观点,并给出了用于更传统设置的体系结构。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.