Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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?

like image 472
Steve Lorimer Avatar asked Jan 29 '26 17:01

Steve Lorimer


1 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).

like image 175
Holt Avatar answered Feb 01 '26 06:02

Holt