1

我在 Python 3.2.2 中使用 ctypes 来封装一些 C 数据结构。最终目标是当结构的数据内容被修改时,能够拥有一个包装 C 结构通知的对象。

代表代码:

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)

这适用于任何简单的数据属性,如“数字”。

>>> s = MyCStruct()
>>> s.attributes_updated
False
>>> s.value = 123
>>> s.attributes_updated
True

由于__setattr__不会通过索引表示法访问 array属性来调用它,因此我想覆盖__setitem__C 结构中作为数组的那些成员的属性。据推测,那时我需要包含对包含对象的引用,以便attributes_updated可以更改包含对象的变量,但我还没有达到能够以方便的方式捕获对数组属性的访问的地步我可以捕获对简单属性的访问。有没有办法对 ctypes 通过_fields_变量创建的可索引对象执行此操作?是否可以__setitem__覆盖s.array?可能有更好的方法来做这件事吗?

理想情况下,这会发生:

>>> s = MyCStruct()
>>> s.attributes_updated
False
>>> s.array[2] = 456
>>> s.attributes_updated
True

编辑后续问题:

多维数组呢?

class MyCStruct(Comm):
    _fields_ = [('number', c_int),
                ('array', (c_int*5)*2]

我错误地期待下面的答案,它非常适用于一维数组,对于任意嵌套的数组也是如此。应该有一种方法可以递归地生成代理对象,以对多维数组执行相同的操作,是吗?语法逃脱了我。

4

1 回答 1

1

我认为一个很好的解决方案是返回一个代理对象而不是数组,然后它可以处理对数组的访问。可能是这样的:

from ctypes import *

class ArrayProxy(object):
    def __init__(self, array, struct):
        self.array = array
        self.struct = struct

    def __setitem__(self, i, val):
        self.array[i] = val
        self.struct.attributes_updated = True

    def __getitem__(self, i):
        item = self.array[i]
        if issubclass(type(item), Array):
            # handle multidimensional arrays
            return ArrayProxy(item, self.struct)
        return item

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)

    def __getattribute__(self, name):
        attr = super(Comm, self).__getattribute__(name)
        if issubclass(type(attr), Array):
            return ArrayProxy(attr, self)
        return attr


class MyCStruct(Comm):
    _fields_ = [('number', c_int),
                ('array', c_int*5),
                ('multiarray', c_int*2*1),]

    def __init__(self):
        Comm.__init__(self)

s = MyCStruct()
print s.array
# <__main__.ArrayProxy object at 0x1b1f3d0> 
print s.attributes_updated
# False
s.array[0] = 1
print s.attributes_updated
# True

s2 = MyCStruct()
s2.multiarray[0][0] = 1
print s2.attributes_updated
# True
于 2012-05-23T21:39:02.097 回答