使用 Pybind11 包装 STL 容器 return 类型
Wrapping STL container return types using Pybind11
我想包装一个 C++ 函数(使用 Pybind11),returns 一个本身包装在智能指针中的 STL 容器。一个例子如下所示。函数重载,所以我必须指定签名。
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include "my_class.h"
typedef std::array<std::complex<double>, 4> ArrayComplex4;
PYBIND11_MAKE_OPAQUE(ArrayComplex4);
namespace py = pybind11;
using namespace my_namespace;
PYBIND11_MODULE(my_module, m) {
py::class_<MyClass>(m, "MyClass", py::dynamic_attr())
.def("my_function", (std::unique_ptr<ArrayComplex4> (MyClass::*)(double)) &MyClass::my_function)
.def("my_function", (std::unique_ptr<ArrayComplex4> (MyClass::*)(double, double)) &MyClass::my_function);
}
模块可以编译,但是当我尝试使用 Python:
中的函数时会报错
TypeError: Unable to convert function return value to a Python type!
我确定我只是为 Pybind11 设置了错误。感谢您的帮助!
编辑
问题肯定出在我尝试绑定 std::Array
数据类型时。我最终修改了代码以使用 std::Vector
然后 Pybind11 没有问题。请参阅下面 AS Mackey 的回答,了解如何绑定 std::Array
容器。
问题可能出在对 ArrayComplex4 数据结构的 PYBIND11_MAKE_OPAQUE 处理上,我无法让它工作,尽管我有空的时候会再看一下。
下面的代码,我确实开始工作,是我迄今为止最接近你的设计的近似值。我使用了一个额外的用户定义的数据结构来包装 std:: elements:
#include <pybind11/pybind11.h>
#include <pybind11/complex.h>
#include <pybind11/stl.h>
#include <memory>
#include <complex>
#include <array>
#include <cmath>
namespace py = pybind11;
typedef std::array<std::complex<double>, 4> ArrayComplex4;
struct ArrayComplex4Holder
{
ArrayComplex4 data;
ArrayComplex4 getData() { return data; }
};
class MyClass {
public:
MyClass() { }
std::unique_ptr<ArrayComplex4Holder> my_function(double x)
{
std::unique_ptr<ArrayComplex4Holder> ph( new ArrayComplex4Holder());
ph->data[0] = std::complex<double>(x);
return ph;
}
std::unique_ptr<ArrayComplex4Holder> my_function(double x, double y)
{
std::unique_ptr<ArrayComplex4Holder> ph( new ArrayComplex4Holder());
ph->data[0] = std::complex<double>(x);
ph->data[1] = std::complex<double>(y);
return ph;
}
};
PYBIND11_MODULE(example, m) {
m.doc() = "pybind11 example"; // optional module docstring
py::class_<ArrayComplex4Holder>(m, "ArrayComplex4Holder")
.def(py::init<>())
.def("getData", &ArrayComplex4Holder::getData);
py::class_<MyClass>(m, "MyClass")
.def(py::init<>())
.def("my_function", (std::unique_ptr<ArrayComplex4Holder> (MyClass::*)(double)) &MyClass::my_function)
.def("my_function", (std::unique_ptr<ArrayComplex4Holder> (MyClass::*)(double, double)) &MyClass::my_function);
}
注意我发现需要额外的 pybind #includes 才能使 python 转换工作。
简单的python代码是:
import sys
sys.path.append('/Volumes/RAID 1/Projects/workspace/Project CPP 1')
import example
p = example.MyClass()
print (p.my_function(1.2345).getData())
print (p.my_function(1.2345, 6.7890).getData())
这会产生以下输出,看起来是正确的:
[(1.2345+0j), 0j, 0j, 0j]
[(1.2345+0j), (6.789+0j), 0j, 0j]
我希望这能给你一个工作的起点。我很想知道您是否找到了更好的选择...此致,AS
我想包装一个 C++ 函数(使用 Pybind11),returns 一个本身包装在智能指针中的 STL 容器。一个例子如下所示。函数重载,所以我必须指定签名。
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include "my_class.h"
typedef std::array<std::complex<double>, 4> ArrayComplex4;
PYBIND11_MAKE_OPAQUE(ArrayComplex4);
namespace py = pybind11;
using namespace my_namespace;
PYBIND11_MODULE(my_module, m) {
py::class_<MyClass>(m, "MyClass", py::dynamic_attr())
.def("my_function", (std::unique_ptr<ArrayComplex4> (MyClass::*)(double)) &MyClass::my_function)
.def("my_function", (std::unique_ptr<ArrayComplex4> (MyClass::*)(double, double)) &MyClass::my_function);
}
模块可以编译,但是当我尝试使用 Python:
中的函数时会报错TypeError: Unable to convert function return value to a Python type!
我确定我只是为 Pybind11 设置了错误。感谢您的帮助!
编辑
问题肯定出在我尝试绑定 std::Array
数据类型时。我最终修改了代码以使用 std::Vector
然后 Pybind11 没有问题。请参阅下面 AS Mackey 的回答,了解如何绑定 std::Array
容器。
问题可能出在对 ArrayComplex4 数据结构的 PYBIND11_MAKE_OPAQUE 处理上,我无法让它工作,尽管我有空的时候会再看一下。
下面的代码,我确实开始工作,是我迄今为止最接近你的设计的近似值。我使用了一个额外的用户定义的数据结构来包装 std:: elements:
#include <pybind11/pybind11.h>
#include <pybind11/complex.h>
#include <pybind11/stl.h>
#include <memory>
#include <complex>
#include <array>
#include <cmath>
namespace py = pybind11;
typedef std::array<std::complex<double>, 4> ArrayComplex4;
struct ArrayComplex4Holder
{
ArrayComplex4 data;
ArrayComplex4 getData() { return data; }
};
class MyClass {
public:
MyClass() { }
std::unique_ptr<ArrayComplex4Holder> my_function(double x)
{
std::unique_ptr<ArrayComplex4Holder> ph( new ArrayComplex4Holder());
ph->data[0] = std::complex<double>(x);
return ph;
}
std::unique_ptr<ArrayComplex4Holder> my_function(double x, double y)
{
std::unique_ptr<ArrayComplex4Holder> ph( new ArrayComplex4Holder());
ph->data[0] = std::complex<double>(x);
ph->data[1] = std::complex<double>(y);
return ph;
}
};
PYBIND11_MODULE(example, m) {
m.doc() = "pybind11 example"; // optional module docstring
py::class_<ArrayComplex4Holder>(m, "ArrayComplex4Holder")
.def(py::init<>())
.def("getData", &ArrayComplex4Holder::getData);
py::class_<MyClass>(m, "MyClass")
.def(py::init<>())
.def("my_function", (std::unique_ptr<ArrayComplex4Holder> (MyClass::*)(double)) &MyClass::my_function)
.def("my_function", (std::unique_ptr<ArrayComplex4Holder> (MyClass::*)(double, double)) &MyClass::my_function);
}
注意我发现需要额外的 pybind #includes 才能使 python 转换工作。
简单的python代码是:
import sys
sys.path.append('/Volumes/RAID 1/Projects/workspace/Project CPP 1')
import example
p = example.MyClass()
print (p.my_function(1.2345).getData())
print (p.my_function(1.2345, 6.7890).getData())
这会产生以下输出,看起来是正确的:
[(1.2345+0j), 0j, 0j, 0j]
[(1.2345+0j), (6.789+0j), 0j, 0j]
我希望这能给你一个工作的起点。我很想知道您是否找到了更好的选择...此致,AS