Swig C++:接口向量<Class object *>
Swig C++: Interfacing vector<Class object *>
基本上,我试图在 python 中创建一个包含不同数据类型值 (float/int/bool/char/list) 的字典的 tuple/list。
我从以下代码中得到:
(<f_p.Bunch; proxy of <Swig Object of type 'Bunch *' at 0x7f4954bdde10> >, <f_p.Bunch; proxy of <Swig Object of type 'Bunch *' at 0x7f4954bdde40> >, <f_p.Bunch; proxy of <Swig Object of type 'Bunch
*' at 0x7f495668be70> >, <f_p.Bunch; proxy of <Swig Object of type 'Bunch *' at 0x7f4952d09a50> >)
我想得到这种形式的输出:
({'I':1.0,'B':2.0, 'C':3.0, 'dert_':[1.2, 2.3, 3.4, 4.5, 5.6]})
我无法处理这个 class 对象指针 (bunch*),也找不到任何解决方案。我在网上查看,但找不到适用于我的案例的有效解决方案。
f_p.cpp:
#include <iostream>
#include "f_p.h"
#define CPP_14 0
std::vector<Bunch*> form_p(const double *array, int x, int y) {
std::vector<Bunch*> v;
Bunch *b1 = new Bunch(5);
b1->set_I_B_C(1.0, 2.0, 3.0);
b1->set_dert_({1.2, 2.3, 3.4, 4.5, 5.6});
float *_dert = b1->get_dert_();
for(int i=0; i<5; i++) {
std::cout << _dert[i] << std::endl;
}
v.push_back(b1);
v.push_back(b1);
v.push_back(b1);
v.push_back(b1);
return v;
}
f_p.h:
#ifndef F_P_H
#define f_P_H
#include <memory>
#include <vector>
#include <memory>
#include <algorithm>
#include <tuple>
#include <initializer_list>
class Bunch {
private:
unsigned int start;
unsigned int end;
float I;
float B;
float C;
bool isPos;
std::unique_ptr<float[]> dert_;
public:
explicit Bunch(size_t width) {
#if CPP_14
this->dert_ = std::make_unique<float[]>(width);
#else
this->dert_ = std::unique_ptr<float[]>(new float[width]);
#endif
std::fill_n(this->dert_.get(), width, -1.0);
}
void set_I_B_C(float I, float B, float C) {
this->I = I;
this->B = B;
this->C = C;
}
std::tuple<float, float, float> get_I_B_C() const {
return std::make_tuple(this->I, this->B, this->C);
}
float* get_dert_() const {
return this->dert_.get();
}
void set_dert_(std::initializer_list<float> l) {
int i = 0;
for (auto e: l){
dert_[i++] = e;
}
}
};
/* Define function prototype */
std::vector<Bunch*> form_p(const double *array, int x, int y) ;
#endif
f_p.i:
%module f_p
#define SWIGPYTHON_BUILTIN
%{
#include "numpy/arrayobject.h"
#define SWIG_FILE_WITH_INIT /* To import_array() below */
#include "f_p.h"
%}
%include "std_map.i"
%import "std_deque.i"
%import "std_vector.i"
%template (mapiv) std::map<char,float>;
%template () std::vector<Bunch*>;
%include "numpy.i"
%init %{
import_array();
%}
%apply (double* IN_ARRAY2, int DIM1, int DIM2) {
(const double* array, int x, int y)
}
%include "f_p.h"
build.sh:
rm *.o f_p_wrap.cpp _f_p.so f_p.py
rm -rf __pycache__
g++ -O3 -march=native -fPIC -c f_p.cpp
swig -python -c++ -o f_p_wrap.cpp f_p.i
# Next, compile the wrapper code:
g++ -O3 -march=native -w -fPIC -c $(pkg-config --cflags --libs python3) -I /home/antpc/anaconda3/lib/python3.7/site-packages/numpy/core/include f_p.cpp f_p_wrap.cpp
g++ -std=c++11 -O3 -march=native -shared f_p.o f_p_wrap.o -o _f_p.so -lm
test_sample.py:
from f_p import form_p
import numpy as np
x = np.random.randn(3, 4)
print(form_p(x))
问题实际上可以归结为:您有一个 class 并且您想将其转换为本机 Python 对象(而不是包装对象)。 SWIG 会自动生成包装对象,但您必须竭尽全力将 C++ 类型转换为本机 Python 类型。
我假设这种简化 Bunch
是为了让类型图更易读一些。您应该能够很容易地使它适应您的 Bunch
。或者,您可以在将 class 传递给 Python.
之前将其转换为这个简单的结构
struct Bunch {
float i, b, c;
std::vector<float> dert;
};
Bunch makeBunch();
下面是makeBunch
的实现。
Bunch makeBunch() {
return {1.0, 2.0, 3.0, {1.2, 2.3, 3.4, 4.5, 5.6}};
}
我省略了错误检查以保持简短。
%typemap(out) Bunch {
$result = PyDict_New();
PyDict_SetItem($result, PyBytes_FromString("I"), PyFloat_FromDouble(.i));
PyDict_SetItem($result, PyBytes_FromString("B"), PyFloat_FromDouble(.b));
PyDict_SetItem($result, PyBytes_FromString("C"), PyFloat_FromDouble(.c));
PyObject *dert = PyList_New(.dert.size());
for (size_t i = 0; i != .dert.size(); ++i) {
PyList_SetItem(dert, i, PyFloat_FromDouble(.dert[i]));
}
PyDict_SetItem($result, PyBytes_FromString("dert_"), dert);
}
当我自己编译并 运行 时,我得到了预期的结果(好吧,足够接近了!)。
>>> import test
>>> test.makeBunch()
{'I': 1.0, 'C': 3.0, 'B': 2.0, 'dert_': [1.2000000476837158, 2.299999952316284, 3.4000000953674316, 4.5, 5.599999904632568]}
类型映射并非绝对必要。您可以改为只使用包装对象。删除类型映射并确保像这样公开 std::vector<float>
。
%include "std_vector.i"
%template(FloatVector) std::vector<float>;
然后您可以通过包装对象访问Bunch
。
>>> import test
>>> bunch = test.makeBunch()
>>> bunch
<test.Bunch; proxy of <Swig Object of type 'Bunch *' at 0x10b6daba0> >
>>> bunch.i
1.0
>>> bunch.b
2.0
>>> bunch.c
3.0
>>> bunch.dert
<test.FloatVector; proxy of <Swig Object of type 'std::vector< float,std::allocator< float > > *' at 0x10b6dadb0> >
>>> for d in bunch.dert:
... print(d)
...
1.20000004768
2.29999995232
3.40000009537
4.5
5.59999990463
一些有信誉的来源:
基本上,我试图在 python 中创建一个包含不同数据类型值 (float/int/bool/char/list) 的字典的 tuple/list。
我从以下代码中得到:
(<f_p.Bunch; proxy of <Swig Object of type 'Bunch *' at 0x7f4954bdde10> >, <f_p.Bunch; proxy of <Swig Object of type 'Bunch *' at 0x7f4954bdde40> >, <f_p.Bunch; proxy of <Swig Object of type 'Bunch
*' at 0x7f495668be70> >, <f_p.Bunch; proxy of <Swig Object of type 'Bunch *' at 0x7f4952d09a50> >)
我想得到这种形式的输出:
({'I':1.0,'B':2.0, 'C':3.0, 'dert_':[1.2, 2.3, 3.4, 4.5, 5.6]})
我无法处理这个 class 对象指针 (bunch*),也找不到任何解决方案。我在网上查看,但找不到适用于我的案例的有效解决方案。
f_p.cpp:
#include <iostream>
#include "f_p.h"
#define CPP_14 0
std::vector<Bunch*> form_p(const double *array, int x, int y) {
std::vector<Bunch*> v;
Bunch *b1 = new Bunch(5);
b1->set_I_B_C(1.0, 2.0, 3.0);
b1->set_dert_({1.2, 2.3, 3.4, 4.5, 5.6});
float *_dert = b1->get_dert_();
for(int i=0; i<5; i++) {
std::cout << _dert[i] << std::endl;
}
v.push_back(b1);
v.push_back(b1);
v.push_back(b1);
v.push_back(b1);
return v;
}
f_p.h:
#ifndef F_P_H
#define f_P_H
#include <memory>
#include <vector>
#include <memory>
#include <algorithm>
#include <tuple>
#include <initializer_list>
class Bunch {
private:
unsigned int start;
unsigned int end;
float I;
float B;
float C;
bool isPos;
std::unique_ptr<float[]> dert_;
public:
explicit Bunch(size_t width) {
#if CPP_14
this->dert_ = std::make_unique<float[]>(width);
#else
this->dert_ = std::unique_ptr<float[]>(new float[width]);
#endif
std::fill_n(this->dert_.get(), width, -1.0);
}
void set_I_B_C(float I, float B, float C) {
this->I = I;
this->B = B;
this->C = C;
}
std::tuple<float, float, float> get_I_B_C() const {
return std::make_tuple(this->I, this->B, this->C);
}
float* get_dert_() const {
return this->dert_.get();
}
void set_dert_(std::initializer_list<float> l) {
int i = 0;
for (auto e: l){
dert_[i++] = e;
}
}
};
/* Define function prototype */
std::vector<Bunch*> form_p(const double *array, int x, int y) ;
#endif
f_p.i:
%module f_p
#define SWIGPYTHON_BUILTIN
%{
#include "numpy/arrayobject.h"
#define SWIG_FILE_WITH_INIT /* To import_array() below */
#include "f_p.h"
%}
%include "std_map.i"
%import "std_deque.i"
%import "std_vector.i"
%template (mapiv) std::map<char,float>;
%template () std::vector<Bunch*>;
%include "numpy.i"
%init %{
import_array();
%}
%apply (double* IN_ARRAY2, int DIM1, int DIM2) {
(const double* array, int x, int y)
}
%include "f_p.h"
build.sh:
rm *.o f_p_wrap.cpp _f_p.so f_p.py
rm -rf __pycache__
g++ -O3 -march=native -fPIC -c f_p.cpp
swig -python -c++ -o f_p_wrap.cpp f_p.i
# Next, compile the wrapper code:
g++ -O3 -march=native -w -fPIC -c $(pkg-config --cflags --libs python3) -I /home/antpc/anaconda3/lib/python3.7/site-packages/numpy/core/include f_p.cpp f_p_wrap.cpp
g++ -std=c++11 -O3 -march=native -shared f_p.o f_p_wrap.o -o _f_p.so -lm
test_sample.py:
from f_p import form_p
import numpy as np
x = np.random.randn(3, 4)
print(form_p(x))
问题实际上可以归结为:您有一个 class 并且您想将其转换为本机 Python 对象(而不是包装对象)。 SWIG 会自动生成包装对象,但您必须竭尽全力将 C++ 类型转换为本机 Python 类型。
我假设这种简化 Bunch
是为了让类型图更易读一些。您应该能够很容易地使它适应您的 Bunch
。或者,您可以在将 class 传递给 Python.
struct Bunch {
float i, b, c;
std::vector<float> dert;
};
Bunch makeBunch();
下面是makeBunch
的实现。
Bunch makeBunch() {
return {1.0, 2.0, 3.0, {1.2, 2.3, 3.4, 4.5, 5.6}};
}
我省略了错误检查以保持简短。
%typemap(out) Bunch {
$result = PyDict_New();
PyDict_SetItem($result, PyBytes_FromString("I"), PyFloat_FromDouble(.i));
PyDict_SetItem($result, PyBytes_FromString("B"), PyFloat_FromDouble(.b));
PyDict_SetItem($result, PyBytes_FromString("C"), PyFloat_FromDouble(.c));
PyObject *dert = PyList_New(.dert.size());
for (size_t i = 0; i != .dert.size(); ++i) {
PyList_SetItem(dert, i, PyFloat_FromDouble(.dert[i]));
}
PyDict_SetItem($result, PyBytes_FromString("dert_"), dert);
}
当我自己编译并 运行 时,我得到了预期的结果(好吧,足够接近了!)。
>>> import test
>>> test.makeBunch()
{'I': 1.0, 'C': 3.0, 'B': 2.0, 'dert_': [1.2000000476837158, 2.299999952316284, 3.4000000953674316, 4.5, 5.599999904632568]}
类型映射并非绝对必要。您可以改为只使用包装对象。删除类型映射并确保像这样公开 std::vector<float>
。
%include "std_vector.i"
%template(FloatVector) std::vector<float>;
然后您可以通过包装对象访问Bunch
。
>>> import test
>>> bunch = test.makeBunch()
>>> bunch
<test.Bunch; proxy of <Swig Object of type 'Bunch *' at 0x10b6daba0> >
>>> bunch.i
1.0
>>> bunch.b
2.0
>>> bunch.c
3.0
>>> bunch.dert
<test.FloatVector; proxy of <Swig Object of type 'std::vector< float,std::allocator< float > > *' at 0x10b6dadb0> >
>>> for d in bunch.dert:
... print(d)
...
1.20000004768
2.29999995232
3.40000009537
4.5
5.59999990463
一些有信誉的来源: