Is there any way to use pythonappend with SWIG's new builtin feature?
I agree with you that using typemap
gets a little messy, but it is the right way to accomplish this task. You are also right that the SWIG documentation does not directly say that %pythonappend
is incompatible with -builtin
, but it is strongly implied: %pythonappend
adds to the Python proxy class, and the Python proxy class does not exist at all in conjunction with the -builtin
flag.
Before, what you were doing was having SWIG convert the C++ std::vector
objects into Python tuples, and then passing those tuples back down to numpy
- where they were converted again.
What you really want to do is convert them once, at the C level.
Here's some code which will turn all std::vector<int>
objects into NumPy integer arrays:
%{#include "numpy/arrayobject.h"%}%init %{ import_array();%}%typemap(out) std::vector<int> { npy_intp result_size = $1.size(); npy_intp dims[1] = { result_size }; PyArrayObject* npy_arr = (PyArrayObject*)PyArray_SimpleNew(1, dims, NPY_INT); int* dat = (int*) PyArray_DATA(npy_arr); for (size_t i = 0; i < result_size; ++i) { dat[i] = $1[i]; } $result = PyArray_Return(npy_arr);}
This uses the C-level numpy functions to construct and return an array. In order, it:
- Ensures NumPy's
arrayobject.h
file is included in the C++ output file - Causes
import_array
to be called when the Python module is loaded (otherwise, all NumPy methods will segfault) - Maps any returns of
std::vector<int>
into NumPy arrays with atypemap
This code should be placed before you %import
the headers which contain the functions returning std::vector<int>
. Other than that restriction, it's entirely self-contained, so it shouldn't add too much subjective "mess" to your codebase.
If you need other vector types, you can just change the NPY_INT
and all the int*
and int
bits, otherwise duplicating the function above.