问题
I have this function:
void func(int* a, int b);
Which I want to make available in python like so:
func(list, int)
ie, the user passes a list and an integer (telling the functions how many entries should be stored in the list). To do this, I need to know the value of "b" in the initialization for "a" (because I need a raw C int array temporarily).
%typemap(in) ( int* a) {
//need to allocate sizeof(int) * b bytes temporarily
}
But I don't know the value of "b" because it is only parsed later!
How can I access the value of the "b" argument?
回答1:
You can use a multi-argument typemap.
%typemap(in) (const int *a, int b) %{
$2 = (int)PyList_Size($input);
$1 = new int[$2];
for(Py_ssize_t i = 0; i < $2; ++i)
$1[i] = PyLong_AsLong(PyList_GET_ITEM($input,i));
%}
%typemap(freearg) (const int* a, int b) %{
delete [] $1;
%}
This assumes you are passing in a list (hence the const int*
). Since a Python list knows its size there is no need to pass the size as well. Also note there is no error checking in the above example.
With this you pass one Python object ($input) for the two parameters. b
($2) is initialized with the size and a
($1) allocates a new int
array of that size. The elements of the array are copied to this array.
The freearg
typemap provides the cleanup after the function is called.
You use it like this:
func([1,2,3,4,5])
If you want to return a list, the following can be used:
%typemap(in) (int *a, int b) %{
$2 = (int)PyLong_AsLong($input);
$1 = new int[$2];
%}
%typemap(argout) (int *a, int b) (PyObject* tmp) %{
tmp = PyList_New($2);
for(Py_ssize_t i = 0; i < $2; ++i)
PyList_SET_ITEM(tmp, i, PyLong_FromLong($1[i]));
$result = SWIG_Python_AppendOutput($result, tmp);
%}
%typemap(freearg) (int* a, int b) %{
delete [] $1;
%}
Note non-const int *a
. Python doesn't need a list as an input parameter to return one, so the input typemap just expects an integer (error checking removed for brevity). The argout typemap builds a Python list out of the values return and appends them to the output result.
Use it like this:
func(5) # returns for example [1,2,3,4,5]
If func
has a return value it will return [retval, [1,2,3,4,5]]
回答2:
I thought I saw that you can use %apply
to copy the typemap-for-array-and-length typemap so SWIG uses it for your function arguments. Something like (can't check exact syntax right now):
%apply (int *ARRAY, int LENGTH) { (int* a, int b) };
void func(int* a, int b);
Alternatly, take a look Converting Python list to a char **: you might be able to adapt it to int by replacing all "char *" with "int".
来源:https://stackoverflow.com/questions/23015860/swig-with-python-and-c-arguments