一个类型只需要注册一个到 Python 的转换。
当通过 暴露类boost::python::class_
时,会发生类型信息和注册。此外,如果boost::noncopyable
未提供,则将T
注册将按值复制的 to-Python 和 from-Python 转换器。用户可以使用 注册自己的自定义转换器boost::python::to_python_converter
。
因此,一种解决方案是禁止使用 类的默认转换器A
,boost::noncopyable
然后注册一个自定义转换器,该转换器将创建 Python 对象,该对象A
包含B
. 这种方法将在 Boost.Python 中使用较低级别的 API 来处理实例创建。
/// @brief Custom converter that converts A to either an A or B Python object.
struct class_A_cref_wrapper
: boost::python::to_python_converter<A, class_A_cref_wrapper>
{
// Type that makes instances that hold A by value.
typedef boost::python::objects::make_instance<A,
boost::python::objects::value_holder<A>
> instance_maker;
static PyObject* convert(const A& a)
{
namespace python = boost::python;
return a.is_B()
? python::incref(python::object(B(a)).ptr()) // Create B.
: instance_maker::execute(boost::ref(a)); // Create A.
}
};
这是一个演示此方法的完整示例:
#include <boost/python.hpp>
// Legacy API.
class A
{
public:
A() : b_(false) {}
A(bool b) : b_(b) {}
bool is_B() const { return b_; } // true if conversion to B will succeed
private:
bool b_;
};
class B: public A
{
public:
B() : A() {}
B(const A& a) : A(a) {}
};
/// @brief Factory functions that return an A type with is_B of false.
A make_A() { return A(false); }
/// @brief Factory functions that return an A type with is_B of true.
A make_B() { return A(true); }
/// @brief Custom converter that converts A to either an A or B Python object.
struct class_A_cref_wrapper
: boost::python::to_python_converter<A, class_A_cref_wrapper>
{
// Make and hold instances by value.
typedef boost::python::objects::make_instance<A,
boost::python::objects::value_holder<A>
> instance_maker;
static PyObject* convert(const A& a)
{
namespace python = boost::python;
return a.is_B()
? python::incref(python::object(B(a)).ptr()) // Create B.
: instance_maker::execute(boost::ref(a)); // Create A.
}
};
BOOST_PYTHON_MODULE(example)
{
namespace python = boost::python;
// Expose A and B classes. Use boost::noncopyable to suppress to-Python
// and from-Python converter regristration for class A.
python::class_<A, boost::noncopyable>("A");
python::class_<B, python::bases<A> >("B");
// Register a custom converter for A.
class_A_cref_wrapper();
// Expose factory functions that always return an A type. This will
// cause to_python converters to be invoked when invoked from Python.
python::def("make_A", &make_A);
python::def("make_B", &make_B);
}
交互使用:
>>> import example
>>> assert(isinstance(example.make_A(), example.A))
>>> assert(isinstance(example.make_B(), example.B))
>>> assert(isinstance(example.make_B(), example.A))
>>> assert(not isinstance(example.make_A(), example.B))