Boost.Python :C++模板类型匹配的嵌套命名空间

Boost.Python : nested namespace matching C++ template types

本文关键字:嵌套 命名空间 类型 Python C++ Boost      更新时间:2023-10-16

尝试使用 Boost.Python 将 python numpy 数组传递给C++,在C++中处理它们,并将进程结果返回给 python:由于数组的类型在C++端模板化,它应该匹配 python 端的嵌套命名空间。

尽管进行了许多测试/谷歌搜索,但尚未找到解决方案。

错误:"Boost.Python.ArgumentError python参数类型与C++签名不匹配":任何线索?...

>> more dummy.hpp dummy.cpp dummy.py 
::::::::::::::
dummy.hpp
::::::::::::::
#include <boost/python.hpp>
#include <boost/python/numpy.hpp>
#include <iostream>
namespace bp = boost::python;
namespace np = boost::python::numpy;
template<typename FD>
class dummy {
public:
dummy() {
Py_Initialize();
np::initialize();
mean = 0.;
};
int doStuffs(np::ndarray & A) {
int szA = A.shape(0);
FD * ptrA = reinterpret_cast<FD*>(A.get_data());
for (int i = 0; i < szA; ++i) {
std::cout << "dummy::doStuffs - " << i << " : " << ptrA[i] << std::endl;
mean += ptrA[i];
}
mean /= szA;
std::cout << "dummy::doStuffs, mean " << mean << std::endl;
return 0;
};
FD mean;
};
template<typename FD>
void exportDummy(std::string const & nested) {
std::string module = "dummy." + nested;
bp::object pyModule(bp::handle<>(bp::borrowed(PyImport_AddModule(module.c_str()))));
bp::scope().attr(nested.c_str()) = pyModule;
bp::scope pyScope = pyModule;
bp::class_<dummy<FD>, boost::noncopyable>(nested.c_str())
.def          ("doStuffs", &dummy<FD>::doStuffs)
.def_readonly ("mean",     &dummy<FD>::mean);
};
::::::::::::::
dummy.cpp
::::::::::::::
#include <boost/python.hpp>
#include <dummy.hpp>
namespace bp = boost::python;
BOOST_PYTHON_MODULE(dummy)
{
// Specify that this module is actually a package.
bp::object package = bp::scope();
package.attr("__path__") = "dummy"; // Setting the __path__ attribute on the module to the name of the module.
// Create modules.
exportDummy<float>("float");
}
::::::::::::::
dummy.py
::::::::::::::
#!/usr/bin/env python
from __future__ import print_function
import numpy as np
from scipy import sparse
n = 4
one = np.array([ 1]*n)
data = np.array([2.*one, -1.*one, -1.*one])
diags = np.array([0, 1, -1])
A = sparse.spdiags(data, diags, n, n)
print("python A ", A.toarray())
import dummy
dummyFloat = dummy.float.float()
dummyFloat.doStuffs(A)
print("python mean", dummyFloat.mean)

我得到:

>> make
g++ -I/usr/include/python2.7 -I. -fPIC -shared -o dummy.so dummy.cpp -lboost_numpy -lboost_python -lpython2.7
>> python dummy.py 
python A  [[ 2. -1.  0.  0.]
[-1.  2. -1.  0.]
[ 0. -1.  2. -1.]
[ 0.  0. -1.  2.]]
Traceback (most recent call last):
File "dummy.py", line 17, in <module>
dummyFloat.doStuffs(A)
Boost.Python.ArgumentError: Python argument types in
float.doStuffs(float, dia_matrix)
did not match C++ signature:
doStuffs(dummy<float> {lvalue}, boost::python::numpy::ndarray {lvalue})

找到解决方案!

>> more dummy.cpp dummy.hpp dummy.py 
::::::::::::::
dummy.cpp
::::::::::::::
#include <boost/python.hpp>
#include <complex>
#include <dummy.hpp>
namespace bp = boost::python;
BOOST_PYTHON_MODULE(dummy)
{
bp::object package = bp::scope();
package.attr("__path__") = "dummy";
exportDummy<float>("float");
exportDummy<complex<float>>("complexFloat");
}
::::::::::::::
dummy.hpp
::::::::::::::
#include <boost/python.hpp>
#include <boost/python/numpy.hpp>
#include <iostream>
namespace bp = boost::python;
namespace np = boost::python::numpy;
using namespace std;
template<typename FD>
class dummy {
public:
dummy() {
Py_Initialize();
np::initialize();
mean = 0.;
};
int doStuffs(np::ndarray & A) {
int szA = A.shape(0);
FD * ptrA = reinterpret_cast<FD*>(A.get_data());
for (int i = 0; i < szA; ++i) {
std::cout << "C++ - dummy::doStuffs - " << i << " : " << ptrA[i] << std::endl;
mean += ptrA[i];
}
mean /= szA;
return 0;
};
FD mean;
};
template<typename FD>
void exportDummy(std::string const & nested) {
std::string module = "dummy";
bp::object pyModule(bp::handle<>(bp::borrowed(PyImport_AddModule(module.c_str()))));
bp::scope pyScope = pyModule;
pyScope.attr(nested.c_str()) = bp::class_<dummy<FD>, boost::noncopyable>(nested.c_str())
.def         ("doStuffs", &dummy<FD>::doStuffs)
.def_readonly("mean",     &dummy<FD>::mean)
;
};
::::::::::::::
dummy.py
::::::::::::::
#!/usr/bin/env python
from __future__ import print_function
import numpy as np
import dummy
A = np.array([1, 2, 3], dtype='float32')
print("python A ", A)
df = dummy.float()
df.doStuffs(A)
print("python mean", df.mean)
A = np.array([1+2j, 3+4j, 5+6j], dtype='complex64')
print("python A ", A)
dcf = dummy.complexFloat()
dcf.doStuffs(A)
print("python mean", dcf.mean)

我得到:

>> make
g++ -I/usr/include/python2.7 -I. -fPIC -shared -o dummy.so dummy.cpp -lboost_numpy -lboost_python -lpython2.7
>> python dummy.py 
python A  [1. 2. 3.]
C++ - dummy::doStuffs - 0 : 1
C++ - dummy::doStuffs - 1 : 2
C++ - dummy::doStuffs - 2 : 3
python mean 2.0
python A  [1.+2.j 3.+4.j 5.+6.j]
C++ - dummy::doStuffs - 0 : (1,2)
C++ - dummy::doStuffs - 1 : (3,4)
C++ - dummy::doStuffs - 2 : (5,6)
python mean (3+4j)