如何使用Cython公开将C ++对象返回给Python的函数? [英] How to expose a function returning a C++ object to Python using Cython?
问题描述
我正在使用Cython构建C ++-> Python绑定,但是我找不到如何从Python方法返回C ++对象的方法。
I'm building C++<->Python bindings using Cython, and I cannot find how to return a C++ object from a Python method.
更多具体来说,当编译如下所示的 peak_detection_.pyx
时,我得到
More specifically, when compiling peak_detection_.pyx
, shown below, I get
peak_detection_.pyx:35:36: Cannot convert 'vector[Peak]' to Python object
最后一行
def getPeaks(self,data):
return self.thisptr.getPeaks(data)
我理解该错误,但是我不介意有关如何解决该错误的帮助/指针。
I understand the error, but I would not mind some help/pointers about how to fix it.
peak_detection.hpp
#ifndef PEAKDETECTION_H
#define PEAKDETECTION_H
#include <string>
#include <map>
#include <vector>
#include "peak.hpp"
class PeakDetection
{
public:
PeakDetection(std::map<std::string, std::string> config);
std::vector<Peak> getPeaks(std::vector<float> &data);
private:
float _threshold;
};
#endif
peak_detection.cpp
#include <iostream>
#include <string>
#include "peak.hpp"
#include "peak_detection.hpp"
using namespace std;
PeakDetection::PeakDetection(map<string, string> config)
{
_threshold = stof(config["_threshold"]);
}
vector<Peak> PeakDetection::getPeaks(vector<float> &data){
Peak peak1 = Peak(10,1);
Peak peak2 = Peak(20,2);
vector<Peak> test;
test.push_back(peak1);
test.push_back(peak2);
return test;
}
peak.hpp
#ifndef PEAK_H
#define PEAK_H
class Peak {
public:
float freq;
float mag;
Peak() : freq(), mag() {}
Peak(float f, float m) : freq(f), mag(m) {}
};
#endif
peak_detection_.pyx
# distutils: language = c++
# distutils: sources = peak_detection.cpp
from libcpp.vector cimport vector
from libcpp.map cimport map
from libcpp.string cimport string
cdef extern from "peak.hpp":
cdef cppclass Peak:
Peak()
cdef class PyPeak:
cdef Peak *thisptr
def __cinit__(self):
self.thisptr = new Peak()
def __dealloc__(self):
del self.thisptr
cdef extern from "peak_detection.hpp":
cdef cppclass PeakDetection:
PeakDetection(map[string,string])
vector[Peak] getPeaks(vector[float])
cdef class PyPeakDetection:
cdef PeakDetection *thisptr
def __cinit__(self, map[string,string] config):
self.thisptr = new PeakDetection(config)
def __dealloc__(self):
del self.thisptr
def getPeaks(self, data):
return self.thisptr.getPeaks(data)
推荐答案
您的问题是cython不知道如何自动将C ++对象 Peak
转换为python包装的版本 PyPeak
。
Your problem here is that cython doesn't know how to automatically convert the C++ object Peak
into the python wrapped version PyPeak
.
一个将复制 Peak实例的版本
getPeaks
返回到 PyPeak
实例列表的code>为:
A version which will copy the instances of Peak
that getPeaks
returns into a list of PyPeak
instances would be:
# distutils: language = c++
# distutils: sources = peak_detection.cpp
from libcpp.vector cimport vector
from libcpp.map cimport map
from libcpp.string cimport string
cdef extern from "peak.hpp":
cdef cppclass Peak:
Peak()
Peak(Peak &)
float freq, mag
cdef class PyPeak:
cdef Peak *thisptr
def __cinit__(self):
self.thisptr = new Peak()
def __dealloc__(self):
del self.thisptr
cdef copy(self, Peak &other):
del self.thisptr
self.thisptr = new Peak(other)
def __repr__(self):
return "<Peak: freq={0}, mag={1}>".format(self.freq, self.mag)
property freq:
def __get__(self): return self.thisptr.freq
def __set__(self, freq): self.thisptr.freq = freq
property mag:
def __get__(self): return self.thisptr.mag
def __set__(self, mag): self.thisptr.mag = mag
cdef extern from "peak_detection.hpp":
cdef cppclass PeakDetection:
PeakDetection(map[string,string])
vector[Peak] getPeaks(vector[float])
cdef class PyPeakDetection:
cdef PeakDetection *thisptr
def __cinit__(self, map[string,string] config):
self.thisptr = new PeakDetection(config)
def __dealloc__(self):
del self.thisptr
def getPeaks(self, data):
cdef Peak peak
cdef PyPeak new_peak
cdef vector[Peak] peaks = self.thisptr.getPeaks(data)
retval = []
for peak in peaks:
new_peak = PyPeak()
new_peak.copy(peak)
retval.append(new_peak)
return retval
一旦编译并运行,我们将获得预期的输出:
Once compiled and run we get the expected output:
In [1]: import peak_detection_
In [2]: print peak_detection_.PyPeakDetection({"_threshold" : "0.01"}).getPeaks([1,2,3])
[<Peak: freq=10.0, mag=1.0>, <Peak: freq=20.0, mag=2.0>]
这篇关于如何使用Cython公开将C ++对象返回给Python的函数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!