Search code examples
pythonc++numpypybind11

How to pass a list of numpy array with pybind


I have a preprocessor written in python. This preprocessor calculate a unknown number of numpy arrays. They are stored inside a list. For further calculation I need to read these list of numpy array in cpp. I dont know howto transform an element of the list into the array type.

main.py

import numpy as np
import myCPPAlgo

my_list = [ np.zeroes(shape=(10, 10), dtype=np.uint32) for _ in range(10)]
myCPPAlgo.call(my_list)

main.cpp

#include <pybind11/pybind11.h>
#include <pybind11/numpy.h>
#include <pybind11/stl.h>

#include <iostream>


namespace py = pybind11;

int call(py::list listOfNumpyArrays)
{
    for( py::handle array: listOfNumpyArrays)
    {
        // howto transform?
        py::array_t<uint32_t> casted_array = ???

        auto requestCastedArray = casted_array.request();
        uint32_t nRows = requestCastedArray.shape[1];
        uint32_t nCols = requestCastedArray.shape[0];
        uint32_t* pBlockedArray = (uint32_t*) requestCastedArray.ptr;
    }
    return 0;
}


PYBIND11_MODULE(myCPPAlgo, m) {
    m.doc() = ""

    m.def("call", &call, "");
}

How can I transform the pybind::handle into the py::array_t?


Solution

  • Simply cast to an array: py::array_t<uint32_t> casted_array = py::cast<py::array>(array);. Full working example (modulo error checking :) ) below.

    #include <pybind11/pybind11.h>
    #include <pybind11/numpy.h>
    #include <pybind11/stl.h>
    
    #include <iostream>
    
    namespace py = pybind11;
    
    int call(py::list listOfNumpyArrays)
    {
        for( py::handle array: listOfNumpyArrays)
        {
            // howto transform?
            py::array_t<uint32_t> casted_array = py::cast<py::array>(array);
    
            auto requestCastedArray = casted_array.request();
            uint32_t nRows = requestCastedArray.shape[1];
            uint32_t nCols = requestCastedArray.shape[0];
            uint32_t* pBlockedArray = (uint32_t*) requestCastedArray.ptr;
            std::cerr << " rows x columns = " << nRows << " x " << nCols << std::endl;
            for (int i = 0; i < nCols; ++i) {
                for (int j = 0; j < nRows; ++j) {
                    std::cerr << pBlockedArray[i*nRows + j] << " ";
                }
                std::cerr << '\n';
            }
        }
        return 0;
    }
    
    PYBIND11_MODULE(myCPPAlgo, m) {
        m.doc() = "";
        m.def("call", &call, "");
    }
    

    and test code:

    import numpy as np
    import myCPPAlgo
    
    my_list = [ np.ones(shape=(3, 10), dtype=np.uint32) for _ in range(10)]
    my_list[9][1, 0] = 42
    myCPPAlgo.call(my_list)