BPL*_*BPL 10 c++ python ctypes wrapper pybind11
考虑这个小 pybind11 包装器 + 测试:
安装程序.py
from pybind11.setup_helpers import Pybind11Extension
from pybind11.setup_helpers import build_ext
from setuptools import setup
setup(
name="wrapper",
ext_modules=[Pybind11Extension("wrapper", ["wrapper.cpp"])],
cmdclass={"build_ext": build_ext},
)
Run Code Online (Sandbox Code Playgroud)
包装器.cpp
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <vector>
namespace py = pybind11;
struct Mesh2d {
public:
Mesh2d(int numVerts, int numTris)
: numVertices(numVerts), numTriangles(numTris) {
vertices = new float[numVerts * 2];
indices = new int[numTris * 3];
}
~Mesh2d() {
delete vertices;
delete indices;
}
void makeVertex(int i, float x, float y) {
vertices[i * 2 + 0] = x;
vertices[i * 2 + 1] = y;
}
void makeTriangle(int i, int a, int b, int c) {
indices[i * 3 + 0] = a;
indices[i * 3 + 1] = b;
indices[i * 3 + 2] = c;
}
float *vertices;
int *indices;
int numVertices;
int numTriangles;
};
PYBIND11_MODULE(wrapper, m) {
m.doc() = "mcve";
py::class_<Mesh2d>(m, "Mesh2d")
.def(py::init<int, int>())
.def("make_vertex", &Mesh2d::makeVertex)
.def("make_triangle", &Mesh2d::makeTriangle)
.def_readonly("vertices", &Mesh2d::vertices)
.def_readonly("indices", &Mesh2d::indices);
}
Run Code Online (Sandbox Code Playgroud)
测试.py
from wrapper import Mesh2d
def test():
m = Mesh2d(3, 1)
m.make_vertex(0, -1.0, -1.0)
m.make_vertex(1, 1.0, -1.0)
m.make_vertex(2, 0.0, 1.0)
m.make_triangle(0, 0, 1, 2)
print(m.vertices.__class__)
print(m.indices.__class__)
test()
Run Code Online (Sandbox Code Playgroud)
问题
现在因为我没有对顶点和索引做任何特殊的事情,所以__class__我在 python 中得到的分别是<class 'float'>和<class 'int'>。将这些原始指针转换为一些合适的对象的正确 pybind11 方法是什么,例如:
array.array("f", vertices)
array.array("I", indices)
(ctypes.c_float * 6)(*vertices)
(ctypes.c_uint * 3)(*indices)
memoryview(struct.pack("6f", *vertices))
memoryview(struct.pack("3I", *indices))
struct.pack("6f", *vertices)
struct.pack("3I", *indices)
Run Code Online (Sandbox Code Playgroud)
我的最终目标是能够在 C++ 端生成非常复杂的大量数据(将实时修改的大量数据)。因此,包装器的开销很小(理想情况下没有任何不必要的复制到 python 数据结构,只需提供原始指针)。
参考
https://pybind11.readthedocs.io/en/stable/advanced/functions.html#return-value-policies
如果我没记错的话,您应该能够numpy以相当便宜的价格使用内存的数组视图(如果不是几乎没有开销)。这是一个完整的例子。
#include <pybind11/pybind11.h>
#include <pybind11/numpy.h>
#include <pybind11/stl.h>
#include <vector>
namespace py = pybind11;
struct Mesh2d {
public:
Mesh2d(int numVerts, int numTris)
: numVertices(numVerts), numTriangles(numTris) {
vertices = new float[numVerts * 2];
indices = new int[numTris * 3];
// these constructors are just views of the memory and will not copy the data
// (nor take ownership of the pointer)
// You could also make these shapes {numVerts, 2} and {numTris, 3} or whatever else is helpful to you.
pyVertices = py::array_t<float>({numVerts * 2}, vertices);
pyIndices = py::array_t<int>({numTris * 3}, indices);
}
~Mesh2d() {
delete vertices;
delete indices;
}
void makeVertex(int i, float x, float y) {
vertices[i * 2 + 0] = x;
vertices[i * 2 + 1] = y;
}
void makeTriangle(int i, int a, int b, int c) {
indices[i * 3 + 0] = a;
indices[i * 3 + 1] = b;
indices[i * 3 + 2] = c;
}
float *vertices;
int *indices;
py::array_t<float> pyVertices;
py::array_t<int> pyIndices;
int numVertices;
int numTriangles;
};
PYBIND11_MODULE(wrapper, m) {
m.doc() = "mcve";
py::class_<Mesh2d>(m, "Mesh2d")
.def(py::init<int, int>())
.def("make_vertex", &Mesh2d::makeVertex)
.def("make_triangle", &Mesh2d::makeTriangle)
.def_readonly("vertices", &Mesh2d::pyVertices)
.def_readonly("indices", &Mesh2d::pyIndices);
}
Run Code Online (Sandbox Code Playgroud)
使用的构造函数py::array_t在这里。如果您正在寻找类似于 C++ 中的 numpy 的东西,我还会向您指出xtensor 。
| 归档时间: |
|
| 查看次数: |
650 次 |
| 最近记录: |