追加C ++创建的对象,以Python列表,并使其通过蟒蛇管理 [英] Append C++ created object to python list and make it managed by python
问题描述
好吧,我已经检查了一会儿,找不到一个答案。
Well, I've been checking this for a while, couldn't find an answer to it.
我要追加其暴露在蟒蛇的对象,说富:
I wanted to append an object which is exposed to python, say Foo:
struct Foo {
Foo(){ std::cout << "Creating a Foo object" << std::endl;}
virtual ~Foo(){ std::cout << "Destroying a Foo object" << std::endl;}
};
我跟富工作继承的对象,并在某些时候我想将它们附加到一个Python列表。对于这一点,我创建了一个FooWrapper,从富继承并使用拷贝构造函数
I work with the Foo inherited objects, and at some point I want to append them to a python list. For this, I created a FooWrapper, which inherits from Foo and use the copy constructor to
struct FooWrapper : public Foo {
FooWrapper(const Foo& foo):Foo(foo){ std::cout << "Creating a copy from foo using FooWrapper" << std::endl;}
virtual ~FooWrapper(){ std::cout << "Destroying a FooWrapper object" << std::endl;}
};
这是暴露在蟒蛇:
BOOST_PYTHON_MODULE(foo_module)
{
using namespace py = boost::python;
py::class_<FooWrapper>("FooWrapper", py::no_init)…
}
我有一个附加的最后foo的方法FooWrapper反对Python列表,说:
I have a method which appends the final Foo objects as FooWrapper to a python list, say:
void appendFoosToList(py::list &list)
{
for ( const Foo* foo : m_foos )
{
list.append( FooWrapper( *foo ) );
}
}
我怎么能做出这样而不是创建一个临时的对象,然后复制到列表中,我追加到列表这个对象,而不必复制临时?
How could I make so that instead of creating a temporary object and then copying to the list, that I append to the list this object, without having to copy the temporary?
我读过很多单证( boost_faq , boost_python_wiki )很多次我拿到这运行时错误:
I've read many documentations (boost_faq, boost_python_wiki), many times I got this runtime error:
类型错误:没有to_python(按值)转换器找到了C ++类型:
TypeError: No to_python (by-value) converter found for C++ type:
BPL无法从Python对象获得C ++价值。
BPL was unable to get C++ value from Python object.
例如,要求提取时(.attr( LEN )())
获取对象的长度你省略()。
For example, when calling extract(.attr("len")()) to get object length you omitted "()".
和没能找到一个解决方案。
And didn't manage to find a solution.
我无法找到一个清晰的文档,所以我来到这里作为最后的手段。
I couldn't find a clear documentation about this, so I come here as the final resort.
推荐答案
在短,分配包装上的可用存储和使用的 manage_new_object
结果转换为所有权转让给Python对象。这将导致Boost.Python的构建Python对象的时候,而不是复制指针对象复制指针。
In short, allocate the wrapper on the free store and use the manage_new_object
result convert to transfer ownership to a Python object. This will cause Boost.Python to copy the pointer when constructing the Python object, rather than copying the pointee.
一个C ++对象嵌入到Python对象。这是 HeldType
暴露通过类_
,默认为C ++类型暴露的类时提供的。通常情况下,露出一个功能时,可以增加,获取与<返回的,并嵌入到Python对象的C ++类型href=\"http://www.boost.org/doc/libs/1_59_0/libs/python/doc/v2/CallPolicies.html#CallPolicies-concept\"相对=nofollow> CallPolicy 实例。尤其是,使用 return_value_policy
CallPolicy用的 manage_new_object
<一个href=\"http://www.boost.org/doc/libs/1_59_0/libs/python/doc/v2/ResultConverter.html#ResultConverterGenerator-concept\"相对=nofollow> ResultConverterGenerator 允许嵌入式是一个指针,而Python对象将管理权。
A C++ object is embedded into the Python object. This is the HeldType
provided when exposing the class via class_
, which defaults to the C++ type being exposed. Often, when exposing a function, one can augment the C++ type that gets returned and embedded into the Python object with CallPolicy instances. In particular, using an instance of the return_value_policy
CallPolicy with a manage_new_object
ResultConverterGenerator allows for the embedded type to be a pointer, and the Python object will manage ownership.
以下功能可被用来传送一个对象到Python所有权未做指针对象的副本:
The following function can be used to transfer ownership of an object to Python without making a copy of the pointee:
/// @brief Transfer ownership to a Python object. If the transfer fails,
/// then object will be destroyed and an exception is thrown.
template <typename T>
boost::python::object transfer_to_python(T* t)
{
// Transfer ownership to a smart pointer, allowing for proper cleanup
// incase Boost.Python throws.
std::unique_ptr<T> ptr(t);
// Use the manage_new_object generator to transfer ownership to Python.
namespace python = boost::python;
typename python::manage_new_object::apply<T*>::type converter;
// Transfer ownership to the Python handler and release ownership
// from C++.
python::handle<> handle(converter(*ptr));
ptr.release();
return python::object(handle);
}
实例:
void appendFoosToList(boost::python::list& list)
{
for (const Foo* foo : m_foos)
{
list.append(transfer_to_python(new FooWrapper(*foo)));
}
}
下面是一个完整的例子示范这种方式:
#include <iostream>
#include <boost/python.hpp>
// Mocks...
class spam
{
public:
spam() { std::cout << "spam(): " << this << std::endl; }
spam(const spam&)
{
std::cout << "spam(const spam&): " << this << std::endl;
}
~spam() { std::cout << "~spam(): " << this << std::endl; }
};
/// @brief Transfer ownership to a Python object. If the transfer fails,
/// then object will be destroyed and an exception is thrown.
template <typename T>
boost::python::object transfer_to_python(T* t)
{
// Transfer ownership to a smart pointer, allowing for proper cleanup
// incase Boost.Python throws.
std::unique_ptr<T> ptr(t);
// Use the manage_new_object generator to transfer ownership to Python.
namespace python = boost::python;
typename python::manage_new_object::apply<T*>::type converter;
// Transfer ownership to the Python handler and release ownership
// from C++.
python::handle<> handle(converter(*ptr));
ptr.release();
return python::object(handle);
}
void append_to_list(boost::python::list& list)
{
list.append(transfer_to_python(new spam()));
}
BOOST_PYTHON_MODULE(example)
{
namespace python = boost::python;
python::class_<spam>("Spam", python::no_init);
python::def("append_to_list", &append_to_list);
}
交互式用法:
>>> import example
>>> spams = []
>>> example.append_to_list(spams)
spam(): 0x25cbd90
>>> assert(type(spams[0]) is example.Spam)
>>> del spams
~spam(): 0x25cbd90
这篇关于追加C ++创建的对象,以Python列表,并使其通过蟒蛇管理的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!