pybind11: convert py::list to std::vector<std::string>

Question:

I have the following sample code which obtains a py::list as the output of evaluating some python code.

I would like to convert it to a std::vector<std::string>, but am getting an error:

conversion from 'pybind11::list' to non-scalar type 
     'std::vector<std::__cxx11::basic_string<char> >' requested

Per the documentation:

When including the additional header file pybind11/stl.h, conversions
between
std::vector<>/std::deque<>/std::list<>/std::array<>/std::valarray<>,
std::set<>/std::unordered_set<>, and std::map<>/std::unordered_map<>
and the Python list, set and dict data structures are automatically
enabled.

As you can see from the below code example, I have included stl.h, but automatic conversion doesn’t work.

#include <iostream>
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/eval.h>

namespace py = pybind11;

py::list func()
{
    py::object scope = py::module_::import("__main__").attr("__dict__");
    return py::eval("[ 'foo', 'bar', 'baz' ]", scope);
}

int main()
{
    Py_Initialize();

    // call the function and iterate over the returned list of strings
    py::list list = func();
    for (auto it : list)
        std::cout << py::str(it) << 'n';

    // error
    // conversion from 'pybind11::list' to non-scalar type 'std::vector<std::__cxx11::basic_string<char> >' requested
    std::vector<std::string> vec = list;
    for (auto str : vec)
        std::cout << str << 'n';

    return 0;
}

I can iterate over the py::list manually and call vector::push_back with each element

// populating the vector manually myself works
std::vector<std::string> vec;
vec.reserve(list.size());
for (auto it : list)
    vec.push_back(py::str(it));

So I guess the linked documentation above only refers to c++ -> python conversions, and not the other way?

What is the recommended way to convert from py::list to std::vector?

Asked By: Steve Lorimer

||

Answers:

You need to call .cast<>:

auto vec = list.cast<std::vector<std::string>>();

<pybind11/stl.h> simply brings specializations of the conversion templates that allow such cast, and that also allow implicit conversion when you bind function with vector arguments or returning vectors (or other standard containers).

Answered By: Holt
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.