Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In Python, how to access a uint16[3] array wrapped by SWIG (i.e. unwrap a PySwigObject)?

This is Python question. I have a variable A

>>> A
<Swig Object of type 'uint16_t *' at 0x8c66fa0>

>>> help(A)
class PySwigObject(object)
  Swig object carries a C/C++ instance pointer

The instance referred by A is a contiguous array uint16[3] and the problem is to gain access to that array from Python.

In Python, how can I create a variable B of length 3, that gives me read/write access to the same memory pointed by the pointer wrapped in A?

I think the problem has two parts:

  1. How to get the pointer out of A. (I think 0x8c66fa0 points to a Swig object, not the wrapped object).
  2. How to initialise some kind of Python array using a memory pointer and a known data type. (Numpy has a frombuffer method, but what seems to be needed is a frommemory method.) Perhaps some casting will be needed.

This should be easy I think, but I've been reading and hacking for more than a day!

To solve the second part, I think an example could begin this way:

>>> import numpy
>>> C = numpy.ascontiguousarray([5,6,7],"uint16")
>>> C
array([5, 6, 7], dtype=uint16)
>>> C.data
<read-write buffer for 0x8cd9340, size 6, offset 0 at 0x8902f00>

Then try to build B (of whatever vector type) using "0x8902f00" and "uint16" and test if changing B[2] causes changes in C[2].

Many thanks for your suggestions or a clear example.

Regards,

Owen

like image 722
Owen Avatar asked Feb 05 '10 18:02

Owen


1 Answers

After more reading and trying stuff out, the answers are as follows:

1. The wrapped pointer in PySwigObject A is available as  A.__long__() .

2. A raw pointer can be cast into an indexable type using ctypes as follows

import ctypes
pA = ctypes.cast( A.__long__(), ctypes.POINTER( ctypes.c_uint16 ) )

Then the elements can be addressed as pA[0], pA[1] etc

pA points to the same memory as the original object, therefore be careful not to use pA after the original object is deleted.

Here is an example for just the second part of the problem (on using a raw pointer of known type in Python),

C = numpy.ascontiguousarray([5,6,7],"uint16")  # make an array
C
rawPointer = C.ctypes.data
pC = ctypes.cast( rawPointer, ctypes.POINTER( ctypes.c_uint16 ))
pC[0:3]
pC[1]=100
pC[0:3]
C

Running the example in Python will show that both C[1] and pC[1] have been changed to 100.

Solved. :)

like image 145
Owen Avatar answered Sep 19 '22 18:09

Owen