[英]Can you create a python class via pybind11?
目前,当使用python + pybind11时,我发现使用类型化的c ++类/结构令人沮丧。
我想更改绑定,以便它们生成具有__init__
和如下所示的简单函数的简单python类。 可行吗?
推理:
我目前有一个通过c ++生成的结构,但是它有很多重的std::vector<float>
,我想传递给python,并以numpy数组的形式保存在类似的接口python类中。 (如果您能告诉我如何快速将向量移动为numpy数组,则可以加分!)
我已经用pybind11完全绑定了我的c ++结构,所以我觉得我知道自己在做什么...但是我似乎不知道这是否可行!
因此,作为一项学习练习,我可以通过pybind11创建以下python类吗?
>>> python
class MyStruct:
def __init__(self, A_in, descriptor_in):
self.A = A_in
self.descriptor = descriptor_in
def add_to_vec(f_in):
self.A.append(f_in)
<<< python
编辑:我想说我“认为”这对于python C api是可行的,但是我想避免直接使用它。 (但是,如果您认为这是唯一的方法,请告诉我:))
Edit2 :(响应@Erwan)
我知道的单独获取类变量的唯一方法是这种方式(如下所示)。 如果要在结构中包含多个numpy数组,则不能使用pybind公告的buffer_protocol
接口。 但是,这需要创建一个仅python接口的函数.def
(不理想),它指向原始数据的(我认为是副本)(所以它可能很慢,我尚未对其进行基准测试,但是我不确定(如果这是hack或将向量放入numpy数组的正确方法)。
#include <pybind11/pybind11.h>
#include <pybind11/numpy.h>
#include <vector>
#include <string>
struct Pet {
Pet(const std::string &name) : name(name) {
bdata.push_back(22.);
bdata.push_back(23.1);
bdata.push_back(24.);
bdata.push_back(2222.);
}
void setName(const std::string &name_) { name = name_; }
const std::string &getName() const { return name; }
std::string name;
std::vector<float> bdata;
};
namespace py = pybind11;
PYBIND11_MODULE(example, m) {
py::class_<Pet>(m, "Pet")
.def(py::init<const std::string &>())
.def("setName", &Pet::setName)
.def("getName", &Pet::getName)
.def("bdata", [](Pet &m) -> py::array {
py::buffer_info buff_info(py::buffer_info(
m.bdata.data(), /* Pointer to buffer */
sizeof(float), /* Size of one scalar */
py::format_descriptor<float>::format(), /* Python struct-style format descriptor */
m.bdata.size() /* Number of dimensions */
));
return py::array(buff_info);
});
}
我不完全理解您的问题,但是我将介绍以下内容:
奖励积分,如果您可以告诉我如何快速将向量移动为numpy数组!
如果将bdata.data()的返回结果与numpy.frombuffer()和bdata.size()结合使用,则可以获取矢量数据视图,从C ++开始,该数据将保证是连续的11。 (在这种情况下,正常的numpy.array()调用将不接受copy = False,但frombuffer的作用类似于强制类型转换。)由于没有副本,因此可能会尽快。
下面是cppyy中的一个示例(该示例可以轻松进行测试,但是对于如何将std :: vector和numpy.array本身混合使用,答案的使用并不重要)。 关键在于最后几行:'arr'的更新将显示在原始矢量(和vv)中,b / c frombuffer是视图,而不是副本:
import cppyy
import numpy as np
# load struct definition
cppyy.cppdef("""
struct Pet {
Pet(const std::string &name) : name(name) {
bdata.push_back(22.);
bdata.push_back(23.1);
bdata.push_back(24.);
bdata.push_back(2222.);
}
void setName(const std::string &name_) { name = name_; }
const std::string &getName() const { return name; }
std::string name;
std::vector<float> bdata;
};""")
# create a pet object
p = cppyy.gbl.Pet('fido')
print(p.bdata[0]) # for reference (prints 22, per above)
# create a numpy view on the std::vector's data
# add count=p.bdata.size() if need be
arr = np.frombuffer(p.bdata.data(), dtype=np.float32)
# prove that it worked as intended
arr[0] = 14
print(p.bdata[0]) # shows update to 14
p.bdata[2] = 17.5
print(arr[2]) # shows update to 17.5
它将打印:
22.0
14.0
17.5
如果调整std :: vector的大小,则“ arr”可能无效。 但是,如果您知道最大大小,并且该大小不是太大或无法完全使用,则可以保留该大小,因此不会重新分配向量的内部数据。
根据存储numpy数组的方式/位置,我还建议将“ p”(因此也就是“ p.bdata”)的生存期绑定到“ arr”。 通过将它们都保留为数据类,作为您所需要的包装器类的实例。
如果要使用C ++进行转换,请使用NumPy的数组API中的PyArray_FromBuffer。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.