繁体   English   中英

您可以通过pybind11创建python类吗?

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM