提高::蟒蟒传递的参考名单:: [英] boost::python passing reference of python::list
问题描述
我真的很想知道是否有传递一个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$c$c>对象。
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 thebooot::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$c$c>接受列表
作为一个恒定的参考,它在构造函数中创建与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屋!