py :: vectorize + type_caster =缺少NumPy类型信息

时间:2018-02-11 21:50:00

标签: python c++ pybind11

在过去的几天里,我一直在使用pybind11为现有的C ++库创建Python绑定,我非常喜欢它!

可悲的是,我只是遇到了一个小问题......

我试图做两件事:

  • 将第三方矢量类型转换为NumPy数组并返回的自定义type_caster

  • 返回此类型的函数,由py::vectorize()自动向量化

这两件事都很适合自己的工作。 带标量输入的矢量化函数也可以很好地工作。

但是,如果我使用数组作为输入调用矢量化函数,则会引发异常:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
RuntimeError: NumPy type info missing for 3vecIdLi2EE

我做错了什么?

或者根本不应该这样做?

以下是我的代码减少到最低限度。在我的实际代码中,vec类是第三方库的一部分,return_vector()在我自己的代码中。

mylib.cpp

#include <pybind11/pybind11.h>
#include <pybind11/numpy.h>

namespace py = pybind11;

template<typename T, int N> struct vec {
  explicit vec(const T* data_) {
    for (int i = 0; i < N; ++i) { this->data[i] = data_[i]; }
  }
  T data[N];
};

vec<double, 2> return_vector(double t) {
  double v[] = {t, t};
  return vec<double, 2>{v};
}

namespace pybind11 { namespace detail {
  template <typename T, int N> struct type_caster<vec<T, N>>
  {
  private:
    using _vecTN = vec<T, N>;

  public:
    PYBIND11_TYPE_CASTER(_vecTN, _("vec<T, N>"));

    bool load(py::handle src, bool convert)
    {
      if (!convert && !py::array_t<T>::check_(src)) { return false; }
      auto buf = py::array_t<T>::ensure(src);
      if (!buf || buf.ndim() != 1 || buf.size() != N) { return false; }
      value = _vecTN{buf.data()};
      return true;
    }

    static py::handle cast(const _vecTN& src,
        py::return_value_policy policy, py::handle parent)
    {
      py::array_t<T> a({N});
      for (auto i = 0; i < N; ++i) { a.mutable_at(i) = src.data[i]; }
      return a.release();
    }
  };
}}

template struct pybind11::detail::type_caster<vec<double, 2>>;

PYBIND11_MODULE(mylib, m) {
  m.def("return_vector", py::vectorize(&return_vector));
}

(请随意评论代码,我可能会做很多错误。我对type_caster代码特别不确定。)

为了完整起见,请点击相应的setup.py

from setuptools import setup, Extension

class get_pybind_include(object):

    def __init__(self, user=False):
        self.user = user

    def __str__(self):
        import pybind11
        return pybind11.get_include(self.user)

ext_modules = [
    Extension(
        'mylib',
        ['mylib.cpp'],
        include_dirs=[
            get_pybind_include(),
            get_pybind_include(user=True),
        ],
        language='c++',
    ),
]

setup(
    name='mylib',
    ext_modules=ext_modules,
    install_requires=['pybind11>=2.2'],
)

我用

编译了扩展模块
python3 setup.py develop

运行此Python代码可以正常工作:

>>> import mylib
>>> mylib.return_vector(1)
array([1., 1.])

然而,当我用数组输入调用它时,我收到一个错误:

>>> mylib.return_vector([2, 3])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
RuntimeError: NumPy type info missing for 3vecIdLi2EE

我希望有一个二维数组,如:

array([[2., 2.],
       [3., 3.]])

1 个答案:

答案 0 :(得分:0)

事实证明np::array没有(但是?)支持返回 int[][] arr1 = {,}; 的函数。

请参阅https://github.com/pybind/pybind11/issues/763