【问题标题】:pybind with array as class attribute以数组作为类属性的pybind
【发布时间】:2018-09-04 16:02:28
【问题描述】:

我想使用 pybind 将以下 C++ 代码包装到 python 中

class Galaxy {

public:
    double x[3];
    double v[3];

};

class GalaxyCatalogue {

public:
    long n_tracers;
    Galaxy *object;

    GalaxyCatalogue(long n_tracers);

    ~GalaxyCatalogue();

};

GalaxyCatalogue::GalaxyCatalogue(long n_tracers) : n_tracers(n_tracers) {

    std::cout << "from galaxies " << n_tracers << std::endl;
    object = new Galaxy[n_tracers];
    std::cout << "has been allocated " << std::endl;

}

GalaxyCatalogue::~GalaxyCatalogue() {

    delete[] object;

}

我遇到的第一个问题是 Galaxy 没有构造函数,所以我不知道该怎么做。即使我声明了一个空的构造函数,我也不知道如何以编译时不会出错的方式处理数组。这是我尝试过的:

#include <pybind11/pybind11.h>
#include <iostream>
namespace py = pybind11;

class Galaxy {
   public:
  Galaxy();
 double x[3];
};

PYBIND11_MODULE(example, m){
  py::class_<Galaxy>(m, "Galaxy")
 .def(py::init<>())
 .def_readwrite("x", &Galaxy::x);
 }

我是这样编译的:

c++ -O3 -Wall -shared -std=c++11 -fPIC `python3 -m pybind11 --includes` gal.cpp -o example`python3-config --extension-suffix`

这是我得到的错误:

In file included from gal.cpp:1:
/home/florpi/.conda/envs/virtualito/include/python3.5m/pybind11/pybind11.h: In instantiation of ‘pybind11::class_<type_, options>& pybind11::class_<type_, options>::def_readwrite(const char*, D C::*, const Extra& ...) [with C = Galaxy; D = double [3]; Extra = {}; type_ = Galaxy; options = {}]’:
gal.cpp:19:33:   required from here
/home/florpi/.conda/envs/virtualito/include/python3.5m/pybind11/pybind11.h:1163:65: error: invalid array assignment
                      fset([pm](type &c, const D &value) { c.*pm = value; }, is_method(*this));
                                                           ~~~~~~^~~~~~~
In file included from gal.cpp:1:

/home/florpi/.conda/envs/virtualito/include/python3.5m/pybind11/pybind11.h:64:5: error: ‘pybind11::cpp_function::cpp_function(Func&&, const Extra& ...) [with Func = pybind11::class_<type_, options>::def_readwrite(const char*, D C::*, const Extra& ...) [with C = Galaxy; D = double [3]; Extra = {}; type_ = Galaxy; options = {}]::<lambda(pybind11::class_<Galaxy>::type&, const double (&)[3])>; Extra = {pybind11::is_method}; <template-parameter-1-3> = void]’, declared using local type ‘pybind11::class_<type_, options>::def_readwrite(const char*, D C::*, const Extra& ...) [with C = Galaxy; D = double [3]; Extra = {}; type_ = Galaxy; options = {}]::<lambda(pybind11::class_<Galaxy>::type&, const double (&)[3])>’, is used but never defined [-fpermissive]
     cpp_function(Func &&f, const Extra&... extra) {
     ^~~~~~~~~~~~

提前谢谢你。

【问题讨论】:

    标签: pybind11


    【解决方案1】:

    在 C++ 中,您不能直接分配给数组,这正是 pybind11 在其包装魔法中试图做的事情。一般来说,C++ 数组对于数值数组来说并不是很好的抽象。正如您所注意到的,您甚至不能说galaxy.x = other_galaxy.x

    最好的办法是使用更高级别的矩阵和向量库,这将 a) 为您提供更好的 C++ 编写体验 b) 表现更好 c) 更干净地映射到 Python

    Eigen 是个不错的选择。 pybind11 自动知道如何将特征矩阵和向量映射到 numpy 数组。你的 Galaxy 会变成:

    class Galaxy {
      public:
        Eigen::Vector3d x;
        Eigen::Vector3d v;
    };
    

    如果您绝对不能这样做,则必须为属性提供手动 getter/setter 函数,您可以在其中自己转换为 Python 类型: https://pybind11.readthedocs.io/en/master/classes.html?highlight=def_property#instance-and-static-fields

    【讨论】:

    • 如果你只使用'lists'并且你不想使用另一个第三方库你也可以使用std::vector,它也被pybind11包裹。
    猜你喜欢
    • 2011-04-25
    • 2022-01-08
    • 1970-01-01
    • 1970-01-01
    • 2013-05-25
    • 2011-07-17
    • 2023-03-13
    • 2015-11-12
    • 2021-04-09
    相关资源
    最近更新 更多