簡體   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