追加C ++创建的对象,以Python列表,并使其通过蟒蛇管理 [英] Append C++ created object to python list and make it managed by python

查看:117
本文介绍了追加C ++创建的对象,以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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆