python - 使用 boost::python 包装 boost::optional

标签 python c++ boost boost-python boost-optional

有没有办法包装boost::optional<T>键入对象以通过 boost::python::class_ 公开它(使用自 BOOST_PYTHON_MODULE)

struct Foo 
{
    boost::optional<int> bar;
};

BOOST_PYTHON_MODULE(module_name)
{
    class_<Foo>("Foo")
    .def_readwrite("bar", &Foo::bar);
}

在这种情况下,我对 Python 的期望是 AttributeError

import module_name
f = module_name.Foo()
print f.bar

作为 bar 的值尚未设置。 和 TypeError

import module_name
f = module_name.Foo()
f.bar = "string"

bar属于 int类型。

另一个相关问题是以同样的方式导出类的对象 boost::python::indexing_suite容器类型。

问题是否可以使用 boost::python 解决?应用程序接口(interface)?

最佳答案

你需要一个 exception translatorpython converters .

异常翻译器

namespace bp = boost::python;

// Custom exceptions
struct AttributeError: std::exception
{
  const char* what() const throw() { return "AttributeError exception"; }
};

struct TypeError: std::exception
{
  const char* what() const throw() { return "TypeError exception"; }
};

// Set python exceptions
void translate(const std::exception& e)
{
  if(dynamic_cast<const AttributeError*>(&e)) 
     PyErr_SetString(PyExc_AttributeError, e.what());
  if(dynamic_cast<const TypeError*>(&e)) 
     PyErr_SetString(PyExc_TypeError, e.what());
}

BOOST_PYTHON_MODULE(module_name)
{
  // Exception translator
  bp::register_exception_translator<AttributeError>(&translate);
  bp::register_exception_translator<TypeError>(&translate);
  ...
}

Python 转换器

template <typename T>
struct to_python_optional
{
  static PyObject* convert(const boost::optional<T>& obj)
  {
    if(obj) return bp::incref(bp::object(*obj).ptr());
    // raise AttributeError if any value hasn't been set yet
    else throw AttributeError();
  }
};

BOOST_PYTHON_MODULE(module_name)
{
  ... 
  bp::to_python_converter<boost::optional<int>,
                          to_python_optional<int> >();
  ...
}

源-python转换器

template<typename T>
struct from_python_optional
{ 
  static void* convertible(PyObject *obj_ptr)
    {
      try { return typename bp::extract<T>::extract(obj_ptr) ? obj_ptr : 0 ; }
      // Without try catch it still raises a TypeError exception
      // But this enables to custom your error message
      catch(...) { throw TypeError(); }
    }

  static void construct(
    PyObject *obj_ptr,
    boost::python::converter::rvalue_from_python_stage1_data* data)
    {
      const T value = typename bp::extract<T>::extract(obj_ptr);

      assert(value);

      void* storage = (
        (bp::converter::rvalue_from_python_storage<boost::optional<T> >*)
        data)->storage.bytes;

      new (storage) boost::optional<T>(value);

      data->convertible = storage;
    }

  from_python_optional()
  {
    bp::converter::registry::push_back(
      &convertible,
      &construct,
      bp::type_id<boost::optional<T> >());
  }
};

BOOST_PYTHON_MODULE(module_name)
{
  ... 
  from_python_optional<int>();
  ...
}

此外,您不能将转换器与def_readwrite (see this FAQ) 一起使用,您必须使用 add_property

BOOST_PYTHON_MODULE(module_name)
{
  ...
  bp::class_<Foo>("Foo")
    .add_property("bar", bp::make_getter(&Foo::bar,
                         bp::return_value_policy<bp::return_by_value>()),
                         bp::make_setter(&Foo::bar,
                         bp::return_value_policy<bp::return_by_value>()));
}

因此,您将在 Python 解释器中获得这些输出:

>>> import module_name
>>> f = module_name.Foo()
>>> print f.bar
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: AttributeError exception
>>> f.bar="string"
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: TypeError exception

关于python - 使用 boost::python 包装 boost::optional,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36485840/

相关文章:

python - 获取与Dataframe中每一行中的最大值相对应的所有列的列表

python - 如何通过索引将 scipy.sparse 矩阵分配给 NumPy 数组?

c++ - 不写入文件的简单 C++ 程序

c++ - 在什么情况下,编译器在比较两种类型时会创建新的临时局部值?

c++ - 推导具有不同值类型的映射的返回类型

Python 3.4 与 numpy、scipy 和 matplotlib 的兼容性

python - 如何使用 .loc 语法创建新列?

c++ - 如何在 C++ 中将类型名 T 转换为字符串

c++ - 向下转换 boost::polymorphic_pointer_downcast 或 boost::dynamic_pointer_cast 哪个更好用

c++ - 使用 boost::unordered_map 时如何计算键冲突?