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