为什么 python-exposed boost::gregorian::date 不是随处可用?

Why isn't python-exposed boost::gregorian::date available everywhere?

我用以下内容公开了 boost::gregorian::date:

date_from_python_date{};
to_python_converter<date, date_to_python_date, true>{};

其中 date_to_python_date 是具有正确转换函数的结构:它将其转换为 python datetime.date。 一些 c++ 函数 return 日期并从 python 调用它们有效。

后期有c++的class

class F {
/// ....
public:
    boost::gregorian::date start;
};

我注册的是:

class_<F, F*, bases<B>>("F")
  .def_readwrite("start", &F::start, "FTD")
;

我在 python 注册日期后执行此操作。 然后,我获得了 F 包装器的一个实例 f。但是,当我打印

f.start

错误是:

No Python class registered for C++ class boost::gregorian::date

简而言之,def_readonly()def_readwrite()使用的return策略将默认使用return_internal_reference for user-defined class types (see make_getter()). This return policy will suppress the use of custom converters. To resolve this, replace def_readonly() and def_readwrite() with add_property(), providing a boost::python::return_value_policy with a type of boost::python::return_by_value

变化:

namespace python = boost::python;
python::class_<F, F*, python::bases<B>>("F")
  .def_readwrite("start", &F::start, "FTD")
;

至:

namespace python = boost::python;
python::class_<F, F*, python::bases<B>>("F")
  .add_property("start",
    python::make_getter(
      &F::start, python::return_value_policy<python::return_by_value>()),
    python::make_setter(
      &F::start, python::return_value_policy<python::return_by_value>()),
    "FTD")
  ;

这里有一个完整的例子demonstrating这个区别:

#include <boost/python.hpp>

/// Mocks...
// Mockup user defined type.
class spam {};
struct egg
{
  spam spam;
};

// Mockup convert that converts spam into 'hello world' strings.
struct spam_converter
{
  static PyObject* convert(const spam&)
  {
    namespace python = boost::python;
    python::str result("hello world");
    return python::incref(result.ptr());
  }
};

BOOST_PYTHON_MODULE(example)
{
  namespace python = boost::python;

   // Enable spam to string converter.
  python::to_python_converter<spam, spam_converter>();

  // Expose egg.
  python::class_<egg>("Egg")
     // Expose egg::spam as spam1, access will fail to find converter.
    .def_readonly("spam1", &egg::spam)
    // Expose egg::spam as spam2, automatic conveter will be found.
    .add_property("spam2", 
      python::make_getter(
        &egg::spam, python::return_value_policy<python::return_by_value>()))
    ;
}

交互使用:

>>> import example
>>> egg = example.Egg()
>>> try:
...     spam = egg.spam1 # expect to throw
...     assert(False)
... except TypeError:
...     assert(True)
...
>>> spam = egg.spam2
>>> assert(spam == "hello world")

请注意,虽然相同的 egg::spam 数据成员实例被公开为 Egg.spam1Egg.spam2,但公开数据成员的方式会影响是否发货时发现自动转换器