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.
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)
Greetings Chris
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.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::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.std::vector
, then C++ has constructed a copy to the Python list. This copy has no association with the original list.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:
And its usage:
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.
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:
Although
boost::python::stl_input_iterator
acceptslist
as a constant reference, it creates a reference to the Python list from within the constructor.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.First, the module needs to have Python initialize the GIL for threading.
For convenience, lets create a simple class to help manage the GIL:
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.
Here is the complete example:
And its usage:
While the Python console blocked for 6 seconds in the
sleep(6)
call, the C++ thread acquired the GIL, displayed the contents of listx
, and released the GIL.