Ich habe ein kleines Projekt, das wunderbar mit SWIG zusammenarbeitet. Insbesondere geben einige meiner Funktionen std::vector
s zurück, die in Python in Tupel übersetzt werden. Jetzt mache ich viele Zahlen, also muss SWIG diese nur in Numpy-Arrays konvertieren, nachdem sie vom C ++ - Code zurückgegeben wurden. Dazu verwende ich in SWIG etwa Folgendes.
%feature("pythonappend") My::Cool::Namespace::Data() const %{ if isinstance(val, tuple) : val = numpy.array(val) %}
(Tatsächlich gibt es mehrere Funktionen mit dem Namen "Daten", von denen einige " val
float" zurückgeben. Deshalb überprüfe ich, ob es sich tatsächlich um ein Tupel handelt.) Dies funktioniert einfach wunderbar.
Aber ich würde auch gerne das benutzen -builtin
Flagge verwenden, die jetzt verfügbar ist. Aufrufe dieser Datenfunktionen sind selten und meist interaktiv, sodass ihre Langsamkeit kein Problem darstellt. Es gibt jedoch auch andere langsame Schleifen, die mit der integrierten Option erheblich beschleunigt werden.
Das Problem ist, dass wenn ich dieses Flag verwende, die Pythonappend-Funktion stillschweigend ignoriert wird. Jetzt gibt Data nur noch einmal ein Tupel zurück. Gibt es eine Möglichkeit, wie ich noch numpy Arrays zurückgeben kann? Ich habe versucht, Typemaps zu verwenden, aber es wurde zu einem riesigen Durcheinander.
Bearbeiten:
Borealid hat die Frage sehr gut beantwortet. Der Vollständigkeit halber füge ich ein paar verwandte, aber subtil unterschiedliche Typkarten hinzu, die ich benötige, da ich als konstante Referenz zurückkehre und Vektoren von Vektoren verwende (nicht starten!). Diese sind so unterschiedlich, dass ich nicht möchte, dass jemand anders herumstolpert, um die kleinen Unterschiede herauszufinden.
%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);
}
%typemap(out) std::vector<std::vector<int> >& {
npy_intp result_size = $1->size();
npy_intp result_size2 = (result_size>0 ? (*$1)[0].size() : 0);
npy_intp dims[2] = { result_size, result_size2 };
PyArrayObject* npy_arr = (PyArrayObject*)PyArray_SimpleNew(2, dims, NPY_INT);
int* dat = (int*) PyArray_DATA(npy_arr);
for (size_t i = 0; i < result_size; ++i) { for (size_t j = 0; j < result_size2; ++j) { dat[i*result_size2+j] = (*$1)[i][j]; } }
$result = PyArray_Return(npy_arr);
}
Bearbeiten 2:
Obwohl nicht ganz das, wonach ich gesucht habe, können ähnliche Probleme auch mit dem Ansatz von @ MONK ( hier erklärt ) gelöst werden .