Verlängere Python mit C, Rückkehr numpy Array gibt Müll

Ich wickle eine C-Datei ein, damit ich sie in Python verwenden kann. Die Ausgabe der C-Funktion ist ein Array von Doppelten. Ich möchte, dass dies ein numpy Array in Python ist. Ich bekomme Müll. Hier ist ein Beispiel, das den Fehler erzeugt.

Zuerst die C-Datei (Fokus auf die letzte Funktionsdefinition, alles andere sollte ok sein):

#include <Python.h> #include <numpy/arrayobject.h> #include <stdio.h> static char module_docstring[] = "docstring"; static char error_docstring[] = "generate the error"; static PyObject *_aux_error(PyObject *self, PyObject *args); static PyMethodDef module_methods[] = { {"error", _aux_error, METH_VARARGS, error_docstring}, {NULL, NULL, 0, NULL} }; PyMODINIT_FUNC init_tmp(void) { PyObject *m = Py_InitModule3("_tmp", module_methods, module_docstring); if (m == NULL) return; /* Load `numpy` functionality. */ import_array(); } static PyObject *_aux_error(PyObject *self ,PyObject *args) { double vector[2] = {1.0 , 2.0}; npy_intp dims[1] = { 2 }; PyObject *ret = PyArray_SimpleNewFromData(1, dims, (int)NPY_FLOAT , vector ); return ret; } 

Kompilation geht OK (von dem, was ich verstehe – ich habe ein Python-Skript verwendet, das alles kompiliert).

In Python, ich laufe das folgende Skript, um mein neues Modul zu testen:

 try: import _tmp res = _tmp.error() print(res) except: print("fail") 

Das Ergebnis, das ich auf dem Bildschirm sehe, ist Müll. Ich habe versucht, (int)NPY_FLOAT mit (int)NPY_FLOAT32, (int)NPY_FLOAT64, (int)NPY_DOUBLE und ich bekomme immer noch Müll. Ich benutze python2.7.

Vielen Dank!!!

EDIT : Nach der Antwort unten habe ich die letzte Funktion geändert:

 static PyObject *_aux_error(PyObject *self, PyObject *args) { double *vector = calloc(2, sizeof(double)); vector[0] = 1.0; vector[1] = 2.0; npy_intp *dims = calloc(1 , sizeof(npy_intp)); dims[1] = 2; PyObject *ret = PyArray_SimpleNewFromData(1, dims, (int)NPY_FLOAT , &vector ); return ret; } 

Jetzt zeigt python ein leeres Array.

3 Solutions collect form web for “Verlängere Python mit C, Rückkehr numpy Array gibt Müll”

Versuchen Sie, dies zu ändern:

 static PyObject *_aux_error(PyObject *self) { 

Dazu:

 static PyObject *_aux_error(PyObject *self, PyObject *args) { 

Python wird das args Argument übergeben, auch wenn Sie Ihre Funktion nicht damit definieren.

Es gibt noch ein grundsätzliches Problem mit deinem Code. Sie haben ein numpy Array mit einem Array, vector , das ist auf dem Stapel erstellt. Wenn _aux_error zurückkehrt, wird dieses Gedächtnis zurückgefordert und kann wiederverwendet werden.

Sie können das Array mit PyArray_SimpleNew() erstellen, um das numpy Array zuzuordnen und dann vector in die Daten des Arrays zu kopieren:

 static PyObject *_aux_error(PyObject *self, PyObject *args) { double vector[2] = {1.0 , 2.0}; npy_intp dims[1] = {2}; PyObject *ret = PyArray_SimpleNew(1, dims, NPY_DOUBLE); memcpy(PyArray_DATA(ret), vector, sizeof(vector)); return ret; } 

Beachten Sie, dass ich den Typ in NPY_DOUBLE geändert NPY_DOUBLE . NPY_FLOAT ist der 32-Bit-Gleitkomma-Typ.


In einem Kommentar fragten Sie nach der dynamischen Zuweisung des Speichers in _aux_error . Hier ist eine Variation des Beispiels, das nützlich sein könnte. Die Länge des Arrays ist noch hartcodiert in dims , also ist es nicht ganz allgemein, aber es könnte ausreichen, um die Frage aus den Kommentaren zu adressieren.

 static PyObject *_aux_error(PyObject *self, PyObject *args) { double *vector; npy_intp dims[1] = {5}; npy_intp k; PyObject *ret = PyArray_SimpleNew(1, dims, NPY_DOUBLE); vector = (double *) PyArray_DATA(ret); /* * NOTE: Treating PyArray_DATA(ret) as if it were a contiguous one-dimensional C * array is safe, because we just created it with PyArray_SimpleNew, so we know * that it is, in fact, a one-dimensional contiguous array. */ for (k = 0; k < dims[0]; ++k) { vector[k] = 1.0 + k; } return ret; } 

Warrens Lösung scheint zu funktionieren, obwohl die Freigabe des C-Array-Speicherblocks zu einem Fehler bei der Kompilierung für mich führt. Ich bekam den Memcopy-Trick, um in der minimalistischen Funktion unten zu arbeiten (Kopieren eines 1D C Arrays zu numpy über den Zeiger), die aus Gründen der Einfachheit keine Argumente einnimmt und dem Leser eine gute Idee geben sollte, wie man dies auf C anwendet Arrays anstelle von Vektoren:

 static PyObject *_cmod_test(PyObject *self, PyObject *args) { double f[5] = {0,1,2,3,4}; int d[1] = {5}; PyObject *c = PyArray_FromDims(1,d,NPY_DOUBLE); memcpy(PyArray_DATA(c), f, 5*sizeof(double)); return c; }; 

Das start.py-Skript ist einfach

 import _cmod _cmod.test() 

Vergessen Sie nicht, die Funktionen zu deklarieren

 #include <Python.h> #include <numpy/arrayobject.h> #define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION static PyObject *_cmod_test(PyObject *self, PyObject *args); 

Irgendwelche Vorschläge für die Verwendung mit PyArray_SimpleNewFromData (während Vermeidung der Speicher Leck Pittfall)? Vielleicht etwas ähnliches wie der gebrochene Code unten.

 static PyObject *_cmod_test(PyObject *self, PyObject *args) { double f[5] = {0,1,2,3,4}; npy_intp dims[1] = {5}; PyObject *c = PyArray_SimpleNewFromData(1, dims, NPY_DOUBLE ,f); PyArray_ENABLEFLAGS(c, NPY_ARRAY_OWNDATA); return c; }; 

Ich empfehle auch Dan Foreman Mackay's Blog auf der Python C API.

Hier ist meine volle Lösung für deine Unterhaltung. Kopieren, Einfügen und Ändern. Offensichtlich ist das Problem, mit dem ich konfrontiert wurde, ein bisschen komplizierter als die obige Frage. Ich habe einige Online-Code von Dan Foreman Mackay benutzt .

Das Ziel meines Codes ist es, einen Kovarianz-Vektor zurückzugeben (was auch immer das ist). Ich habe eine C-Datei namens aux.c , die ein neu zugeordnetes Array zurückgibt:

 #include "aux.h" #include <math.h> #include <stdlib.h> double *covVec(double *X, double *x, int nvecs, int veclen) { double r = 1.3; double d = 1.0; double result; double dist; int n; double *k; k = malloc(nvecs * sizeof(double)); int row; for( row = 0 ; row < nvecs ; row++) { result = 0.0; for (n = 0; n < veclen; n++) { dist = x[n] - X[row*veclen + n]; result += dist * dist; } result = d*exp( -result/(2.0*r*r) ); k[row] = result; } return k; } 

Dann brauche ich eine sehr kurze Header-Datei namens aux.h :

 double *covVec(double *X, double *x, int nvecs, int veclen); 

Um diese zu python zu verpacken habe ich _aux.c :

 #include <Python.h> #include <numpy/arrayobject.h> #include "aux.h" #include <stdio.h> static char module_docstring[] = "This module provides an interface for calculating covariance using C."; static char cov_vec_docstring[] = "Calculate the covariances between a vector and a list of vectors."; static PyObject *_aux_covVec(PyObject *self, PyObject *args); static PyMethodDef module_methods[] = { {"cov_vec", _aux_covVec, METH_VARARGS, cov_vec_docstring}, {NULL, NULL, 0, NULL} }; PyMODINIT_FUNC init_aux(void) { PyObject *m = Py_InitModule3("_aux", module_methods, module_docstring); if (m == NULL) return; /* Load `numpy` functionality. */ import_array(); } static PyObject *_aux_covVec(PyObject *self, PyObject *args) { PyObject *X_obj, *x_obj; /* Parse the input tuple */ if (!PyArg_ParseTuple(args, "OO", &X_obj, &x_obj )) return NULL; /* Interpret the input objects as numpy arrays. */ PyObject *X_array = PyArray_FROM_OTF(X_obj, NPY_DOUBLE, NPY_IN_ARRAY); PyObject *x_array = PyArray_FROM_OTF(x_obj, NPY_DOUBLE, NPY_IN_ARRAY); /* If that didn't work, throw an exception. */ if (X_array == NULL || x_array == NULL ) { Py_XDECREF(X_array); Py_XDECREF(x_array); return NULL; } /* What are the dimensions? */ int nvecs = (int)PyArray_DIM(X_array, 0); int veclen = (int)PyArray_DIM(X_array, 1); int xlen = (int)PyArray_DIM(x_array, 0); /* Get pointers to the data as C-types. */ double *X = (double*)PyArray_DATA(X_array); double *x = (double*)PyArray_DATA(x_array); /* Call the external C function to compute the covariance. */ double *k = covVec(X, x, nvecs, veclen); if ( veclen != xlen ) { PyErr_SetString(PyExc_RuntimeError, "Dimensions don't match!!"); return NULL; } /* Clean up. */ Py_DECREF(X_array); Py_DECREF(x_array); int i; for(i = 0 ; i < nvecs ; i++) { printf("k[%d] = %f\n",i,k[i]); if (k[i] < 0.0) { PyErr_SetString(PyExc_RuntimeError, "Covariance should be positive but it isn't."); return NULL; } } npy_intp dims[1] = {nvecs}; PyObject *ret = PyArray_SimpleNew(1, dims, NPY_DOUBLE); memcpy(PyArray_DATA(ret), k, nvecs*sizeof(double)); free(k); return ret; } 

Ich habe eine Python-Datei namens setup_cov.py :

 from distutils.core import setup, Extension import numpy.distutils.misc_util setup( ext_modules=[Extension("_aux", ["_aux.c", "aux.c"])], include_dirs=numpy.distutils.misc_util.get_numpy_include_dirs(), ) 

Ich kompiliere von der Befehlszeile mit python2.7 setup_cov.py build_ext --inplace . Dann laufe ich die folgende python test date:

 import numpy as np import _aux as a nvecs = 6 veclen = 9 X= [] for _ in range(nvecs): X.append(np.random.normal(size= veclen)) X = np.asarray(X) x = np.random.normal(size=veclen) k = a.cov_vec(X,x) print(k) 
  • General Dekorateur zu wrap versuchen außer in Python?
  • Wie schreibe ich einen Wrapper über Funktionen und Member-Funktionen, die einige Code vor und nach der Wrapped-Funktion ausführt?
  • Exposing `defaultdict` als regelmäßiges` dict`
  • Löschen Sie älteste Dateien auf voller Festplatte
  • Bringe eine Struktur zu Python von C ++ mit BOOST.python zurück
  • Python-Wrapper verhindert Funktionsaufruf?
  • Mac Caffe CUDA Fahrer Problem
  • Python: wickle alle Funktionen in einer Bibliothek ein
  • Java Wrapper auf Perl / Python Code
  • Wie wickle ich einen xmlrpc-Funktionsaufruf ein?
  • Führen Sie ein MATLAB-Skript aus python + pass args
  • Python ist die beste Programmiersprache der Welt.