可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I know, there are often many ways to solve certain problems. But here I know which way I want to have it, but I am unable to make it work with Python and SWIG...
I have a C-function, which returns me an array of double values:
double *my(int x) { double a,b,*buf; buf = malloc (x * sizeof(double)); a=3.14; b=2.7; buf[0]=a; buf[1]=b; return buf; }
Here, I definitively want to have the array as a return value. Not, as in many examples a 'void' function, which writes into an input array. Now, I would like to get a SWIG-python wrapper, which might be used as:
>>> import example >>> print example.my(7) [3.14,2.7]
Whatever I do, I have some conceptual problems here - I always get s.th. like <Swig Object of type 'double *' at 0xFABCABA12>
I tried to define some typemaps in my swg file:
%typemap(out) double [ANY] { int i; $result = PyList_New($1_dim0); for (i = 0; i < $1_dim0; i++) { PyObject *o = PyFloat_FromDouble((double) $1[i]); PyList_SetItem($result,i,o); } }
But still I am unable to get out my results as required. Does anyone have a simple code-example to achieve this task?
回答1:
The first problem is that your typemap doesn't match, you'll need a %typemap(out) double * { ... }
since your function returns a pointer to double and not a double array.
If your list is of fixed size (i.e. an integer literal) as in the example you gave (which I assume is not what you want) you could simply change the typemap as I gave above and exchange $1_dim0
for the fixed size.
Otherwise your problem is that your %typemap(out) double *
cannot possibly know the value of your parameter int x
. You could return a struct that carries both the pointer and the size. Then you can easily define a typemap to turn that into a list (or a NumPy array, see also my response to Wrap C struct with array member for access in python: SWIG? cython? ctypes?).
Incidentally it's not possible to return a fixed sized array in C (see also this answer: Declaring a C function to return an array), so a %typemap(out) double [ANY] { ... }
can never match.
回答2:
I suffered similar problem and solved it in following way.
// example.i %module example %include "carrays.i" %array_class(float, floatArray); float * FloatArray(int N); float SumFloats(float * f);
# ipython > a = example.floatArray(23) # array generated by swig's class constructor > a <example.floatArray; proxy of <Swig Object of type 'floatArray *' at 0x2e74180> > > a[0] -2.6762280573445764e-37 # unfortunately it is created uninitialized.. > b = example.FloatArray(23) # array generated by function > b <Swig Object of type 'float *' at 0x2e6ad80> > b[0] --------------------------------------------------------------------------- TypeError Traceback (most recent call last) # ..... TypeError: 'SwigPyObject' object is not subscriptable > #But there is a way to access b!! > p = example.floatArray_frompointer(b) # i found this function by example. and twice tab > p <example.floatArray; proxy of <Swig Object of type 'floatArray *' at 0x2e66750> > > p[0] 0.0 > p[0] = 42 > p[0] 42.0
Fortunately, all of these types (float *, floatArray *, and proxy of floatArray *) may be successfully passed to C++ function (such as SumFloats).
回答3:
You might want to look at the documentation around carray.i:
%include "carrays.i" %array_class(int, intArray);
http://www.swig.org/Doc2.0/Python.html#Python_nn48
回答4:
If you don't mind pulling in the numpy python module in your python code, you can do the following:
In the SWIG interface file:
%{ #define SWIG_FILE_WITH_INIT %} %include "numpy.i" %init %{ import_array(); %} %apply(float ARGOUT_ARRAY1[ANY]) {(float outarray1d[9])}; void rf(float outarray1d[9]);
Only the last two lines are specific to this example, the first stuff is default for numpy.i (see the numpy.i documentation elsewhere: http://docs.scipy.org/doc/numpy/reference/swig.interface-file.html).
In the C file (can also be inlined in .i file):
void rf(float outarray1d[9]) { float _internal_rf[9]; /* ... */ memcpy(outarray1d, _internal_rf, 9*sizeof(float)); }
Then you have a function which you can call from python as
import mymodule a = mymodule.rf() # a is a numpy array of float32's, with len 9
Now, if you don't want to be forced to pull in the numpy module in your python project, then I suggest you check numpy.i to see how they do the %typemap trick -- as I understand it, it's done with SWIG typemaps and not inherently tied to numpy - should be possible to do the same trick with tuples or lists as return value.
回答5:
I don't know how much C you know - so apologies if I'm teaching you to suck eggs here...
There is no Array class in plain-ole C. An array is always a pointer to a piece of memory, not a "thing" in itself and therefore cannot just be printed-out by itself.
In this case - your "buf" is of type "double *". AFAICRem, if you want to print out the actual values stored at "the memory pointed-to by buf" you have to deallocate each one eg (in pseudocode): for i = 0 to buflength print buf[i]