bp :: extract将bp :: object转换为特定类型。 问题是怎么做副歌?
我们假设我有一个PointContainer和Point类。 我需要一个具有这种签名的功能
bp::object get_point(const PointContainer &, const bp::object & input);
应检查输入参数是否为整数。在这种情况下,它返回PointContainer中具有相应索引的Point实例的引用。 如果它不是整数,那么函数检查输入是否是切片对象(例如mylist [1:10:2])。在这种情况下,它返回PointContainer的副本。
问题是如何将Point,PointContainer实例转换为bp :: objects?
有关上述课程的一些细节
class_<Point<int>>("Point")
.def("__getitem__", get_point_item)
.def("__setitem__", set_point_item)
.def("__len__", get_point_size)
.def("__str__", print_point)
.def("__eq__", &Point<int>::operator ==)
.def("__ne__", &Point<int>::operator !=)
.def("set_x", &Point<int>::set_x)
.def("get_x", &Point<int>::get_x)
.def("set_y", &Point<int>::set_y)
.def("get_y", &Point<int>::get_y)
;
typedef std::vector<Point<int>> PointContainer;
typedef boost::shared_ptr<PointContainer> PointContainerPtr;
class_<PointContainer, PointContainerPtr>("PointContainer")
.def("__iter__", iterator<PointContainer>())
.def("__getitem__", get_point)
.def("__setitem__", set_point)
.def("__len__", &PointContainer::size)
.def("append", push_point)
.def("reserve", &PointContainer::reserve)
.def("clear", &PointContainer::clear)
;
答案 0 :(得分:5)
对于通过boost::python::class_
公开类型的C ++对象,可以使用以下constructor构建一个带有C ++对象实例的Python对象:
template <class T> explicit object(T const& x);
效果:将
x
转换为python并管理对它的引用。抛出:
error_already_set
如果无法进行此类转换,则会设置PythonTypeError
异常。
当通过boost::python::class_
公开某个类型时,Boost.Python将为C ++类型注册-python和from-python转换器。当使用object()
的模板化构造函数时,它将检查内部注册表中的to-python转换器并在找到时使用它。生成的Python对象将拥有并拥有自己的C ++对象实例。
以下是从C ++对象构建boost::python::object
的完整最小示例demonstrating:
#include <boost/python.hpp>
// Mockup types.
class spam {};
class egg {};
// Factory function that returns boost::python::objects.
boost::python::object make_object(std::string name)
{
namespace python = boost::python;
if (name == "spam") return python::object(spam{});
else if (name == "egg") return python::object(egg{});
else return python::object();
}
BOOST_PYTHON_MODULE(example)
{
namespace python = boost::python;
// Expose models.
python::class_<spam>("Spam", python::init<>());
python::class_<egg>("Egg", python::init<>());
// Expose factory function.
python::def("make_object", &make_object);
}
交互式使用:
>>> import example
>>> assert(type(example.make_object("spam")) is example.Spam)
>>> assert(type(example.make_object("egg")) is example.Egg)
>>> assert(example.make_object("bogus") is None)
如果需要不同的返回值语义,例如boost::python::object
应该引用现有的C ++对象而不是副本,那么在包装C ++函数时需要提供call policies。
答案 1 :(得分:0)
诀窍是使用 g_python_point_container_class 变量来实例化其包装的PointContainer类实例,以便能够使用bp :: object处理它。 提到的全局变量在declare_pt_container()函数中初始化。
P.S。拥有全局对象是C ++中的禁忌。为简单起见,我在这个样本中做到了。
bp::object g_python_point_container_class;
bp::object get_point(const PointContainer & points, const bp::object & input) {
bp::extract<bp::slice> slice_extractor(input);
if (slice_extractor.check()) {
const bp::slice & slice = slice_extractor;
if (slice.start().is_none() &&
slice.stop().is_none() &&
slice.step().is_none()) {
// copy entire container
bp::object obj = g_python_point_container_class(points);
return obj;
}
else {
throw ExceptionBaseError("random slicing is not implemented");
}
}
bp::extract<int> int_extractor(input);
if (int_extractor.check()) {
// convert Point to bp::object in the same way using
// extracted integer as an index ....
}
throw ExceptionTypeError("only integer or slice object is expected");
}
PointContainerPtr point_container_constructor_empty() {
return PointContainerPtr(boost::make_shared<PointContainer>());
}
PointContainerPtr point_container_constructor_copy(
const PointContainer & pt_container) {
return PointContainerPtr(boost::make_shared<PointContainer>(pt_container));
}
void declare_pt_container() {
g_python_point_container_class =
class_<PointContainer, PointContainerPtr>("PointContainer", no_init)
.def("__init__", make_constructor(point_container_constructor_empty))
.def("__init__", make_constructor(point_container_constructor_copy))
.def("__iter__", iterator<PointContainer>())
.def("__getitem__", get_point)
.def("__setitem__", set_point)
.def("__len__", &PointContainer::size)
.def("append", push_point)
.def("reserve", &PointContainer::reserve)
.def("clear", &PointContainer::clear)
;
}
BOOST_PYTHON_MODULE(PythonModuleName) {
declare_pt_container();
}