[SWIG][] is a Simplified Wrapper and Interface Generator. It makes it very easy to provide a quick-and-dirty wrapper so you can call code written in [[C]] or [[C++|Cpp]] from code written in another (e.g. [[Python]]). I don't do much with SWIG, because while building an object oriented wrapper in SWIG is possible, I could never get it to feel natural (I like [[Cython]] better). Here are my notes from when I *do* have to interact with SWIG. `%array_class` and memory management ==================================== `%array_class` (defined in [carrays.i][]) lets you wrap a C array in a class-based interface. The example from the [docs][] is nice and concise, but I was [running into problems][comedilib-patch]. >>> import example >>> n = 3 >>> data = example.sample_array(n) >>> for i in range(n): ... data[i] = 2*i + 3 >>> example.print_sample_pointer(n, data) Traceback (most recent call last): ... TypeError: in method 'print_sample_pointer', argument 2 of type 'sample_t *' I just bumped into these errors again while trying to add an `insn_array` class to [[Comedi]]'s wrapper: %array_class(comedi_insn, insn_array); so I decided it was time to buckle down and figure out what was going on. All of the non-Comedi examples here are based on my [[example test code|array_class-example.tar.gz]]. The basic problem is that while you and I realize that an `array_class`-based instance is interchangable with the underlying pointer, SWIG does not. For example, I've defined a `sample_vector_t` `struct`: typedef double sample_t; typedef struct sample_vector_struct { size_t n; sample_t *data; } sample_vector_t; and a `sample_array` class: %array_class(sample_t, sample_array); A bare instance of the double array class has fancy SWIG additions for getting and setting attributes. The class that adds the extra goodies is SWIG's *proxy class*: >>> print(data) # doctest: +ELLIPSIS > However, C functions and structs interact with the bare pointer (i.e. without the proxy goodies). You can use the `.cast()` method to remove the goodies: >>> data.cast() # doctest: +ELLIPSIS >>> example.print_sample_pointer(n, data.cast()) >>> vector = example.sample_vector_t() >>> vector.n = n >>> vector.data = data Traceback (most recent call last): ... TypeError: in method 'sample_vector_t_data_set', argument 2 of type 'sample_t *' >>> vector.data = data.cast() >>> vector.data # doctest: +ELLIPSIS So `.cast()` gets you from `proxy of ` to ``. How you go the other way? You'll need this if you want to do something extra fancy, like accessing the array members ;). >>> vector.data[0] Traceback (most recent call last): ... TypeError: 'SwigPyObject' object is not subscriptable The answer here is the `.frompointer()` method, which can function as a [class method][classmethod]: >>> reconst_data = example.sample_array.frompointer(vector.data) >>> reconst_data[n-1] 7.0 Or as a single line: >>> example.sample_array.frompointer(vector.data)[n-1] 7.0 I chose the somewhat awkward name of `reconst_data` for the reconstitued data, because if you use `data`, you clobber the earlier `example.sample_array(n)` definition. After the clobber, Python garbage collects the old `data`, and becase the old data claims it owns the underlying memory, Python frees the memory. This leaves `vector.data` and `reconst_data` pointing to unallocated memory, which is probably not what you want. If keeping references to the original objects (like I did above with `data`) is too annoying, you have to manually tweak the [ownership flag][ownership]: >>> data.thisown True >>> data.thisown = False >>> data = example.sample_array.frompointer(vector.data) >>> data[n-1] 7.0 This way, when `data` is clobbered, SWIG doesn't release the underlying array (because `data` no longer claims to own the array). However, `vector` doesn't own the array either, so you'll have to remember to reattach the array to somthing that will clean it up before vector goes out of scope to avoid leaking memory: >>> data.thisown = True >>> del vector, data For deeply nested structures, this can be annoying, but it will work. [[!tag tags/tools]] [[!tag tags/C]] [[!tag tags/Python]] [SWIG]: http://www.swig.org/ [carrays.i]: http://www.swig.org/Doc2.0/Library.html#Library_carrays [docs]: http://www.swig.org/Doc2.0/Library.html#Library_carrays [comedilib-patch]: http://comedi.org/git?p=comedi/comedilib.git;a=blobdiff;f=swig/comedi.i;h=5da6160d91d206d007e20c9ac5091d1735afdd30;hp=581997542927fd31cd2e0d03c220377774cfa600;hb=3fe8e6baac051d80906c6fac6c18c04c8df9ce4a;hpb=880074831499ba68c17a1c2653d71d6eef3b9cfb [classmethod]: http://docs.python.org/library/functions.html#classmethod [ownership]: http://www.swig.org/Doc2.0/Python.html#Python_nn30