SWIG Python Structure Array

2024/11/16 15:40:02

I've been searching for a few days trying to figure out how to turn an array of structures into a Python list. I have a function that returns a pointer to the beginning of the array.

struct foo {int member;
};struct foo *bar() {struct foo *t = malloc(sizeof(struct foo) * 4);... do stuff with the structs ...return t;
}

After calling the function from Python I get a single structure but trying to access the other elements of the array causes an error:

foo = bar()
print foo[1].member
TypeError: 'foo' object does not support indexing

I've tried using %array_class but to no avail. I've also tried defining the function as returning an array in the SWIG interface file:

extern struct foo [ANY] bar();

The SWIG documentation is pretty thorough but I can't seem to figure this out.

Answer

The idea you tried with [ANY] won't work for several reasons. Primarily though ANY can be used in typemaps to allow the same typemap to work with varying fixed size arrays, which isn't what you've got there.

The syntax for C isn't quire right there either. You can't write:

int[4] bar() {static int data[4];return data;
}

Or:

int bar()[4] {static int data[4];return data;
}

In standard C. The closest you can get is:

int (*bar())[4] {static int data[4] = {1,2,3,4};return &data;
}

But that's not really any easier to wrap.

However, the simple solution can be made to work using %array_class, for example:

%module test%inline %{struct foo {int member;};struct foo *bar() {struct foo *arr = malloc(sizeof(struct foo) * 4);for (int i = 0; i < 4; ++i) arr[i].member = i;return arr;}
%}%include <carrays.i>
%array_class(struct foo, fooArray);

This lets me do:

Python 3.2.3 (default, May  3 2012, 15:54:42) 
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import test
>>> arr = test.fooArray.frompointer(test.bar())
>>> arr
<test.fooArray; proxy of <Swig Object of type 'fooArray *' at 0xb6f332a8> >
>>> arr[0]
<test.foo; proxy of <Swig Object of type 'struct foo *' at 0xb6f33038> >
>>> arr[1]
<test.foo; proxy of <Swig Object of type 'struct foo *' at 0xb6f33380> >
>>> arr[2]
<test.foo; proxy of <Swig Object of type 'struct foo *' at 0xb6f33398> >
>>> arr[3]
<test.foo; proxy of <Swig Object of type 'struct foo *' at 0xb6f330c8> >
>>> 

We can go one step better though (possibly) by injecting the code to to covert the pointer to the array type automatically, by adding the following before bar() is seen by SWIG:

%pythonappend bar() %{# Wrap it automaticallyval = fooArray.frompointer(val)
%}

So you can now use it like:

Python 3.2.3 (default, May  3 2012, 15:54:42) 
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import test
>>> test.bar()[1].member
1
>>> arr = test.bar()
>>> arr[3].member
3

You need to be careful about memory ownership. In these examples so far the memory is leaked. You can use %newobject to tell SWIG that the memory is owned by the Python side, but then it will get released too early (as soon as the original return value is no longer referenced) so you would need to arrange to keep the original value around longer. A complete example of that, which saves the original pointer inside the instance of the array class to keep a reference around as long as the array wrapper itself would be:

%module test%pythonappend bar() %{# Wrap it automaticallynewval = fooArray.frompointer(val)newval.ptr_retain = valval = newval
%}%newobject bar();%inline %{struct foo {int member;};struct foo *bar() {struct foo *arr = malloc(sizeof(struct foo) * 4);for (int i = 0; i < 4; ++i) arr[i].member = i;return arr;}
%}%include <carrays.i>
%array_class(struct foo, fooArray);

Notice though that the array class this generates is unbounded, exactly like a struct foo* in C. This means you can't iterate over it in Python - the size is unknown. If the size is genuinely fixed, or you have a way of knowing the size somehow you can wrap this in a much nicer (in my view) way by writing a typemap that returns a PyList. It's a bit more work to write, but makes the interface seem nicer on the Python side.

https://en.xdnf.cn/q/71331.html

Related Q&A

Hashing tuple in Python causing different results in different systems

I was practicing tuple hashing. In there I was working on Python 2.7. Below is the code:num = int(raw_input()) num_list = [int(x) for x in raw_input().split()] print(hash(tuple(num_list)))The above cod…

ctypes pointer into the middle of a numpy array

I know how to get a ctypes pointer to the beginning of a numpy array:a = np.arange(10000, dtype=np.double) p = a.ctypes.data_as(POINTER(c_double)) p.contents c_double(0.0)however, I need to pass the po…

Extracting unsigned char from array of numpy.uint8

I have code to extract a numeric value from a python sequence, and it works well in most cases, but not for a numpy array.When I try to extract an unsigned char, I do the followingunsigned char val = b…

How to hold keys down with pynput?

Im using pynput and I would like to be able to hold keys down, specifically wasd but when I try and run this code it only presses the key and doesnt hold it for 2 seconds. If anyone knows what Im doing…

How well does your language support unicode in practice?

Im looking into new languages, kind of craving for one where I no longer need to worry about charset problems amongst inordinate amounts of other niggles I have with PHP for a new project.I tend to fin…

analogy to scipy.interpolate.griddata?

I want to interpolate a given 3D point cloud:I had a look at scipy.interpolate.griddata and the result is exactly what I need, but as I understand, I need to input "griddata" which means some…

Mongodb TTL expires documents early

I am trying insert a document into a Mongo database and have it automatically expire itself after a predetermine time. So far, my document get inserted but always get deleted from the database from 0 -…

sqlalchemy, hybrid property case statement

This is the query Im trying to produce through sqlalchemySELECT "order".id AS "id", "order".created_at AS "created_at", "order".updated_at AS "u…

Whats the newest way to develop gnome panel applets (using python)

Today Ive switched to GNOME (from XFCE) and found some of the cool stuff missing and I would like to (try to) do them on my own. I tried to find information on how to develop Gnome applets (items you p…

How to install opencv-python in python 3.8

Im having problem during the installation of opencv-python in pycharm. After opening pycharm I click on settings and then project interpreter, I click on + and search for the correct module, I started …