I am using ctypes in Python 3.2.2 to encapsulate some C data structures. The ultimate goal is to be able to have an object that wraps a C structure notice when the structure’s data
contents have been modified.
Representative code:
from ctypes import *
class Comm(Structure):
def __init__(self):
self.attributes_updated = False
def __setattr__(self, name, value):
super(Comm, self).__setattr__('attributes_updated', True)
super(Comm, self).__setattr__(name, value)
class MyCStruct(Comm):
_fields_ = [('number', c_int),
('array', c_int*5)]
def __init__(self):
Comm.__init__(self)
This works great for any simple data attribute like ‘number’.
>>> s = MyCStruct()
>>> s.attributes_updated
False
>>> s.value = 123
>>> s.attributes_updated
True
Since __setattr__ is not invoked for accesses via index notation to the
array attribute, I would thus like to override the __setitem__ attribute for those members of the C struct that are arrays. Presumably, at that point I would need to include a reference back to the containing object so that the containing object’s attributes_updated variable could be changed, but I’ve not gotten to the point where I am able to trap accesses to array attributes in the convenient way that I can trap accesses to simple attributes. Is there a way to do this on the indexable objects that ctypes creates via the _fields_ variable? Is it possible to override __setitem__ on s.array? Might there be a better way to go about doing this?
Ideally, this would happen:
>>> s = MyCStruct()
>>> s.attributes_updated
False
>>> s.array[2] = 456
>>> s.attributes_updated
True
Edit for follow-up question:
How about a multidimensional array?
class MyCStruct(Comm):
_fields_ = [('number', c_int),
('array', (c_int*5)*2]
I mistakenly expected the answer below, which works brilliantly for single dimensional arrays to do the same for arbitrarily nested ones. There should be a way to recursively spawn proxy objects to do the same thing for arrays with more than one dimension, yes? The syntax escapes me.
I think a nice solution would be to return a proxy object instead of the array, which can then handle the access to the array. Could be something like this: