【问题标题】:Python function as Argument in C++Python 函数作为 C++ 中的参数
【发布时间】:2014-11-08 18:44:49
【问题描述】:

我正在尝试使用 Boost.Python 在 python 中公开 eigen3。

我找不到暴露functionunaryExpr (const CustomUnaryOp &func=CustomUnaryOp())的方法

我想要的是能让我做这样的事情:

蟒蛇

import libMatrix as mat
a = mat.Matrix(10, 10)
mat.unary_expr( lambda x : 1)

你有什么想法吗?它可能看起来像这样:

void unary_expr(Matrix const& self, PyObject* callable_object)
{
   cpp_callable = ??(callable_object)
   self.unaryEpxr(cpp_callable);
}

=== 我试过的:========================================= ==

1) 我尝试使用简单的回调定义

typedef double(*UnaryExprType)(double);
void unary_expr(Matrix const& self, UnaryExprType a);
    {
       self.unaryEpxr( a );
    }

但 boost 不会将 python 函数转换为 UnaryExprType。

2)我试过implement a structPythonCallBack,但是还是不行,我得到了python签名与c++签名不匹配的错误。

struct PythonCallBackBase
{
public:
    virtual ~PythonCallBackBase()   {}
    virtual double operator() (double const & x) {  return 0;   }
};

struct PythonCallBack : PythonCallBackBase, boost::python::wrapper<PythonCallBackBase>
{
public:
    typedef boost::python::wrapper<PythonCallBackBase> wrap;

    double default_op(double const & x)
    {
        return 0;
    }

    double operator() (double const & x)
    {
        if (boost::python::override f = wrap::get_override("__call__"))
            return f(x);
        return PythonCallBackBase::operator ()(x);
    }
};

void unary_expr(Matrix const& self, PythonCallBack a)
{
   self.unaryEpxr( a );
}

错误信息

ArgumentError: Python argument types in
    Matrix.unary_expr(Matrix, Boost.Python.class)
did not match C++ signature:
    unary_expr(Eigen::Matrix<double, -1, -1, 0, -1, -1>, PythonCallBack)
    unary_expr(Eigen::Matrix<double, -1, -1, 0, -1, -1>, double (*)(double))

【问题讨论】:

标签: python c++ c boost boost-python


【解决方案1】:

Boost.Python 旨在最大程度地减少与PyObject 交互的需求,人们通常可以像在Python 中处理对象一样简单地使用boost::python::object。例如,如果func 是一个引用lambda x: 1boost::python::object,那么下面是带有注释的Python cmets 的以下Boost.Python 用法:

// >>> func = lambda x: 1
boost::python::object func = ...;
// >>> result = func(42)
boost::python::object result = func(42);
// >>> assert(1 == result)
assert(1 == boost::python::extract<int>(result));

在这种情况下,由于 C++ 代码可能期望函子的返回值是 C++ 类型而不是泛型 boost::python::object,因此可以使用包装器类型来适配函子。

/// @brief Auxiliary type that adapts a Boost.Python object to a
///        unary functor with an explicit return type.
template <typename Arg, typename Result>
class py_unary_functor
{
public:

  typedef Arg argument_type;
  typedef Result result_type;

  py_unary_functor(boost::python::object object)
    : object_(object)
  {}

  result_type operator()(argument_type a1)
  {
    return boost::python::extract<result_type>(object_(a1))();
  }

private:
  boost::python::object object_;
};

这是一个完整的最小示例:

#include <boost/python.hpp>

/// @brief Mockup matrix class.
struct matrix
{
  template <typename CustomUnaryOp>
  void unaryExpr(CustomUnaryOp func)
  {
    value = func(value);
  }

  double value;
};

/// @brief Auxiliary type that adapts a Boost.Python object to a
///        unary functor with an explicit return type.
template <typename Arg, typename Result>
class py_unary_functor
{
public:

  typedef Arg argument_type;
  typedef Result result_type;

  py_unary_functor(boost::python::object object)
    : object_(object)
  {}

  result_type operator()(argument_type a1)
  {
    return boost::python::extract<result_type>(object_(a1))();
  }

private:
  boost::python::object object_;
};

/// @brief Auxiliary function used to adapt matrix::unaryExpr.
void matrix_unaryExpr(
  matrix& self,
  boost::python::object object)
{
  py_unary_functor<double, double> func(object);
  return self.unaryExpr(func);
}

BOOST_PYTHON_MODULE(example)
{
  namespace python = boost::python;
  python::class_<matrix>("Matrix")
    // Expose auxiliary function.
    .def("unaryExpr", &matrix_unaryExpr)
    .add_property("value", &matrix::value, &matrix::value)
    ;
}

互动使用:

>>> import example
>>> matrix = example.Matrix()
>>> matrix.value = 21
>>> assert(21 == matrix.value)
>>> matrix.unaryExpr(lambda x: x*2)
>>> assert(42 == matrix.value)

【讨论】:

    最近更新 更多