提高::蟒蟒传递的参考名单:: [英] boost::python passing reference of python::list

查看:119
本文介绍了提高::蟒蟒传递的参考名单::的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我真的很想知道是否有传递一个Python列表来一个boost :: python的C ++ DLL的引用的可能性。我想实现的是,我有一个Python列表,它可以在C随时阅读++。
比方说,你必须在C ++中保存的参考列表中的变量。

I'd really like to know if there is a possibility to pass a reference of a python list to a boost::python c++ dll. What I want to achieve is that I have a list in python which can be read in c++ at any time. Let's say you'd have a variable in C++ that holds the reference to the list.

有没有办法做到这一点?到目前为止,我只发现在Python的ctypes的,我可以做基本的C类型,在这种情况下,没有帮助的引用。

Is there any way to do this? So far I only found the ctypes in python where I can make references of primitive c types, which in this case, doesn't help.

我很高兴的任何建议或解决方法(一个简单的例子将是巨大的)

I am happy for any suggestions or workarounds (a simple example would be great)

问候
克里斯

推荐答案

在短,Boost.Python的保持Python的参数传递的语义与TypeWrappers。因此,在Python传递一个列表时暴露的C ++函数,可以创建一个参考,通过接受Python列表作为<一个保持href=\"http://www.boost.org/doc/libs/1_54_0/libs/python/doc/v2/list.html\"><$c$c>boost::python::list对象。

In short, Boost.Python maintains Python argument passing semantics with its TypeWrappers. Thus, when passing a list in Python to an exposed C++ function, a reference can be created and maintained by accepting the Python list as a boost::python::list object.

详细的答案实际上有更多的深入到它。在深入研究它之前,我在一些语义扩展,以避免混乱。随着Python的垃圾收集和传递通过对象语义,一般的经验法则是治疗Boost.Python的TypeWrappers为智能指针。

The detailed answer actually has a bit more depth to it. Before delving into it, let me expand upon some semantics to avoid confusion. With Python's garbage collection and pass-by-object semantics, the general rule of thumb is to treat the Boost.Python TypeWrappers as smart pointers.


  • 如果该函数接受列表作为的boost ::蟒蛇::列表对象,那么C ++现在已经到了Python对象的引用。 Python的名单的寿命将延长至至少只要 booot ::蟒蛇::列表对象。

  • 如果在Python列表转换为不同的类型,如的std ::矢量,那么C ++构建了一个拷贝到Python列表。此副本与原始列表中没有任何关联。

  • If the function accepts the list as a boost::python::list object, then C++ now has a reference to the Python object. The Python list's lifetime will be extended to be at least as long as the booot::python::list object.
  • If the Python list is converted to a different type, such as std::vector, then C++ has constructed a copy to the Python list. This copy has no association with the original list.

下面是一个可以传递一个Python列表中的C ++模块的一个简单的例子,保持它的句柄,并打印其内容:

Here is a simple example of a C++ module that can be passed a Python list, maintain a handle to it, and print its contents:

#include <iostream> // std::cout
#include <utility>  // std::make_pair
#include <boost/foreach.hpp>
#include <boost/python.hpp>
#include <boost/python/stl_iterator.hpp>

boost::python::list list;

/// @brief Store handle to the list.
///
/// @param pylist Python list for which a handle will be maintained.
void set(const boost::python::list& pylist)
{
  // As the boost::python::list object is smart-pointer like, this
  // creates a reference to the python list, rather than creating a 
  // copy of the python list.
  list = pylist;
}

// Iterate over the current list, printing all ints.
void display()
{
  std::cout << "in display" << std::endl;
  typedef boost::python::stl_input_iterator<int> iterator_type;
  BOOST_FOREACH(const iterator_type::value_type& data, 
                std::make_pair(iterator_type(list), // begin
                               iterator_type()))    // end
  {
    std::cout << data << std::endl;
  }
}

BOOST_PYTHON_MODULE(example) {
  namespace python = boost::python;
  python::def("set",     &set);
  python::def("display", &display);
}

和其用法:

>>> import example
>>>
>>> x = range(2)
>>> x
[0, 1]
>>> example.set(x)
>>> example.display()
in display
0
1
>>> x[:] = range(7, 10)
>>> example.display()
in display
7
8
9


在一个问题带来的复杂性是阅读在C Python列表++在欲望的随时。在它的最复杂的情​​况下,的任何时间的可发生在任何时间点上,从一个C ++线程内


One complexity introduced in the question is the desire to read the Python list in C++ at any time. In its most complicated case, any time can occur at any point in time, from within a C++ thread.

让我们从基础开始:Python的全球国米preTER锁定(GIL)。总之,GIL是周围的间preTER互斥。如果一个线程在做任何影响蟒蛇管理对象的引用计数,那么它必须已经获得了GIL。有时候引用计数也不是很透明的,可以考虑:

Lets start with the basics: Python's Global Interpreter Lock (GIL). In short, the GIL is a mutex around the interpreter. If a thread is doing anything that affects reference counting of python managed object, then it needs to have acquired the GIL. Sometimes the reference counting is not very transparent, consider:

typedef boost::python::stl_input_iterator<int> iterator_type;
iterator_type iterator(list);

虽然<一个href=\"http://www.boost.org/doc/libs/1_54_0/libs/python/doc/v2/stl_iterator.html\"><$c$c>boost::python::stl_input_iterator接受列表作为一个恒定的参考,它在构造函数中创建与Python列表的引用。

Although boost::python::stl_input_iterator accepts list as a constant reference, it creates a reference to the Python list from within the constructor.

在previous例如,没有C ++线程,而GIL已经收购了发生的一切行动。但是,如果显示()可在任何时候从C ++中调用,那么一些设置需要发生。

In the previous example, as there were no C++ threads, all actions occurred while the GIL had been acquired. However, if display() could be invoked at any time from within C++, then some setup needs to occur.

首先,模块需要有Python的初始化GIL穿线。

First, the module needs to have Python initialize the GIL for threading.

BOOST_PYTHON_MODULE(example) {
  PyEval_InitThreads(); // Initialize GIL to support non-python threads.
  ...
}

为了方便起见,让我们创建一个简单的类来帮助管理GIL:

For convenience, lets create a simple class to help manage the GIL:

/// @brief RAII class used to lock and unlock the GIL.
class gil_lock
{
public:
  gil_lock()  { state_ = PyGILState_Ensure(); }
  ~gil_lock() { PyGILState_Release(state_);   }
private:
  PyGILState_STATE state_;
};

要显示具有一个C ++螺纹相互作用,可以添加功能模块,这将允许应用程序调度时要显示的列表中的内容,一个延迟

To show interactions with a C++ thread, lets add functionality to the module that will allow the application to schedule a delay for when the list's contents to be displayed.

/// @brief Entry point for delayed display thread.
///
/// @param Delay in seconds.
void display_in_main(unsigned int seconds)
{
  boost::this_thread::sleep_for(boost::chrono::seconds(seconds));
  gil_lock lock; // Acquire GIL.
  display();     // Can safely modify python objects.
  // GIL released when lock goes out of scope.
}

/// @brief Schedule the list to be displayed.
///
/// @param Delay in seconds.
void display_in(unsigned int seconds)
{
  // Start detached thread.
  boost::thread(&display_in_main, seconds).detach();
}

下面是完整的例子:

#include <iostream> // std::cout
#include <utility>  // std::make_pair
#include <boost/foreach.hpp>
#include <boost/python.hpp>
#include <boost/python/stl_iterator.hpp>
#include <boost/thread.hpp>

boost::python::list list;

/// @brief Store handle to the list.
///
/// @param pylist Python list for which a handle will be maintained.
void set(const boost::python::list& pylist)
{
  list = pylist;
}

// Iterate over the current list, printing all ints.
void display()
{
  std::cout << "in display" << std::endl;
  typedef boost::python::stl_input_iterator<int> iterator_type;
  BOOST_FOREACH(const iterator_type::value_type& data, 
                std::make_pair(iterator_type(list), // begin
                               iterator_type()))    // end
  {
    std::cout << data << std::endl;
  }
}

/// @brief RAII class used to lock and unlock the GIL.
class gil_lock
{
public:
  gil_lock()  { state_ = PyGILState_Ensure(); }
  ~gil_lock() { PyGILState_Release(state_);   }
private:
  PyGILState_STATE state_;
}; 

/// @brief Entry point for delayed display thread.
///
/// @param Delay in seconds.
void display_in_main(unsigned int seconds)
{
  boost::this_thread::sleep_for(boost::chrono::seconds(seconds));
  gil_lock lock; // Acquire GIL.
  display();     // Can safely modify python objects.
  // GIL released when lock goes out of scope.
}

/// @brief Schedule the list to be displayed.
///
/// @param Delay in seconds.
void display_in(unsigned int seconds)
{
  // Start detached thread.
  boost::thread(&display_in_main, seconds).detach();
}

BOOST_PYTHON_MODULE(example) {
  PyEval_InitThreads(); // Initialize GIL to support non-python threads.

  namespace python = boost::python;
  python::def("set",        &set);
  python::def("display",    &display);
  python::def("display_in", &display_in);
}

和其用法:

>>> import example
>>> from time import sleep
>>> 
>>> x = range(2)
>>> example.set(x)
>>> example.display()
in display
0
1
>>> example.display_in(3)
>>> x[:] = range(7, 10)
>>> print "sleeping"
sleeping
>>> sleep(6)
in display
7
8
9

虽然受阻,持续6秒在 Python的控制台睡眠(6)调用,C ++线程获得了GIL,显示列表的内容 X ,并发布了GIL。

While the Python console blocked for 6 seconds in the sleep(6) call, the C++ thread acquired the GIL, displayed the contents of list x, and released the GIL.

这篇关于提高::蟒蟒传递的参考名单::的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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